반응 후크 트립와이어

16765 단어 reactjavascript
미국 국립 기록 보관소에서 공개 도메인에 공개한 이미지

React hooks는 간단하고 강력하지만 간단하고 강력한 많은 것들처럼 쉽게 올무에 빠질 수 있는 고유한 트립와이어가 있습니다.
  • 평가 후크: 너무 적거나 전혀 또는 너무 많음
  • 너무 일찍 구독 취소함
  • 마운트 해제 후 상태 변경

  • 내 후크는 언제 평가됩니까?


  • useRef - 절대, 메모된 참조만 얻을 수 있습니다
  • .
  • useCallback , useEffect - 마운트 시, 마운트 해제 시 및 종속성이 이전 종속성과 다를 때마다
  • useLayoutEffect - 사용 효과와 동일하지만 해당 구성 요소가 렌더링된 후에만

  • 업데이트가 누락되었거나 불필요하거나 루프를 일으키는 경우 간과하기 쉽습니다.

    업데이트가 없거나 없음



    세 가지 오류로 인해 업데이트가 누락될 수 있습니다.
  • 변경을 트리거해야 하는 상태 값을 추적하기 위해 useRef 대신 useState 사용
  • 후크의 종속성 변경을 트리거해야 하는 상태 값을 잊어버림
  • 현재 구성 요소의 부모가 아닌 다른 구성 요소의 상태를 사용하여 변경 시 렌더링 주기를 트리거하지 않음

  • 처음 두 가지에 대한 솔루션은 분명하지만 세 번째 솔루션에는 이상적인 솔루션이 없습니다. 상태를 부모로 가져오거나 대신 컨텍스트를 사용할 수 있습니다.

    불필요한 업데이트



    카운트다운 후크의 다음 예를 고려하십시오.

    const useCountdown = (props) => {
      const [time, setTime] = useState(props.delay)
    
      useEffect(() => {
        const interval = setInterval(() => {
          if (time <= 0) {
            props.onEnded()
            clearInterval(interval)
          } else {
            setTime(time - 0.1)
          }
        }, 100)
        return () => clearInterval(interval)
      }, [time, props.onEnded])
    
      return time
    }
    

    time가 변경될 때마다 이전 평가의 구독 취소가 호출되고 후크가 10분의 1초마다 새로 평가됩니다. 이러한 경우에 함수를 평가하는 setState의 기능은 정말 도움이 됩니다.

    const useCountdown = (props) => {
      const [time, setTime] = useState(props.delay)
    
      useEffect(() => {
        const interval = setInterval(() => {
          setTime((time) => {
            if (time <= 0) {
              props.onEnded()
              clearInterval(interval)
            }
            return time - 0.1
          })
        }, 100)
        return () => clearInterval(interval)
      }, [props.onEnded])
    
      return time
    }
    


    이제 useEffect 종속성에서 잃을 수 있으므로time 불필요한 평가를 피할 수 있습니다.

    useCallback, useMemo, useRef로 수정할 수 있는 메모이제이션 외부에 함수, 배열, 객체, 인스턴스 등을 할당하는 경우 불필요한 업데이트의 또 다른 클래스가 발생할 수 있습니다.

    너무 일찍 구독 취소됨




    const useGlobalClick = (props) => {
      useEffect(() => {
        document.addEventListener('click', props.handler)
        return document.removeEventListener('click', props.handler)
      }, [props.handler])
    }
    
    const useSubscription = (props) => {
       useEffect(() => {
         const subscription = props.observable.subscribe(props.handler)
         return subscription.unsubscribe()
       }, [props.observable, props.handler])
    }
    


    오류를 발견할 수 있습니까?

    첫 번째 예제에서는 return () => document.removeEventListener… 여야 하고 두 번째 예제에서는 return subscription.unsubscribe 또는 return () => subscription.unsubscribe() 여야 합니다. 확실히 하려면 항상 익명 함수를 반환하는 습관을 들이십시오.

    마운트 해제 후 상태 변경



    가져오기 요청, 약속 또는 콜백이 평가되기를 기다리는 것과 같은 비동기 효과를 처리하는 경우 효과를 사용하는 구성 요소가 마운트 해제된 후에만 대기를 종료하는 이벤트가 발생할 수 있습니다.

    const List = () => {
      const [items, setItems] = useState([])
    
      useEffect(() => {
        fetch('my-items')
          .then((response) => response?.json())
          .then((items) => setItems(items ?? []))
      }, [])
    
      return items 
        ? <ul>
            {items.map((item) => <li>{item}</li>)}
          </ul>
        : null
    }
    


    비동기 작업을 중단할 수 있고 그렇게 하면 이점이 있는 경우(예: 다른 사람의 속도를 늦추는 요청) 그렇게 해야 합니다.

    const List = () => {
      const [items, setItems] = useState([])
    
      useEffect(() => {
        const controller = new AbortController()
        fetch('my-items', { signal: controller.signal })
          .then((response) => response?.json())
          .then((items) => setItems(items ?? []))
        return () => controller.abort()
      }, [])
    
      return items 
        ? <ul>
            {items.map((item) => <li>{item}</li>)}
          </ul>
        : null
    }
    


    하지만 그렇지 않다면 어떻게 될까요? ref를 사용하여 setter를 저장하고 마운트 해제 시 null로 설정합니다.

    const List = () => {
      const [items, _setItems] = useState([])
      const setItems = useRef(_setItems)
    
      useEffect(() => {
        fetch('my-items')
          .then((response) => response?.json())
          .then((items) => setItems.current?.(items ?? []))
        return () => { setItems.current = null }
      }, [])
    
      return items 
        ? <ul>
            {items.map((item) => <li>{item}</li>)}
          </ul>
        : null
    }
    


    읽어주셔서 감사합니다. 다른 일반적인 트립와이어를 알고 계시다면 댓글로 알려주세요!

    좋은 웹페이지 즐겨찾기