1 minute read

useState/useRef 와 setTimeout/setInterval

setTimeout/setInterval 에는 useRef
  • useState 와 useRef

    • useState

      상태 유지 값과 그 값을 갱신하는 함수를 반환하며 state 변할 시 리렌더링 큐에 등록

    • useRef

      .current 프로퍼티로 전달된 인자로 초기화된 변경 가능한 ref 객체 반환

      반환된 객체는 컴포넌트 전 생애유지 통해 유지됨

  • setTimeout/setInterval 에서의 차이

    • useState

      
          const [number, setNumber] = useState(0)
      
          let timer = setInterval(()=> {
              setNumber(number + 1)
              console.log(number)
          }, 1000)
      
          // 0 loop
      
      

      1초 단위로 0 만 출력

  • useRef

    
        const number = useRef(0)
    
        let timer = setInterval(()=> {
            number.current = number.current + 1
            console.log(number)
        }, 1000)
    
        // 0, 1, 2, 3, 4
    
    

    1초 단위로 0 부터 1씩 더해서 출력

  • 왜 차이가 생기냐?

    • useState

      prevState 와 nextState 를 비교하고 변경함

      setInterval 의 내부 callback 의 closure 에는 prevState 를 참조함

      참조로 인하여 prevState 는 메모리에 남게되고 가비지 컬렉터의 영향을 받지 않음

      setStae 로 state 를 변경하더라도 closure 에 의해 state 값은 변경되지 않고 console 에는 같은 값이 찍힘

    • useRef

      순수한 JS 객체를 생성함

      useState 처럼 값을 비교하는 과정이 없음

      .current 로 값을 변경하면 JS 객체도 그래도 변경됨

      setInterval 의 내부 callback 의 closure 에는 변경되는 .current 를 참조함

      .current 로 값을 변경 시 값은 변경되고 console 에는 다른 값이 찍힘

  • setInterval/setTimeout 에 useState 를 사용하고 싶다면?

    
      const number = useRef(0)
      const [numberState, setNumberState] = 0
    
      let timer = setInterval(()=> {
          number.current = number.current + 1
          setNumberState(number.current)
          console.log(number)
      }, 1000)
    
      // 0, 1, 2, 3, 4
    
    

    state 값을 참조하는게 아니라 useRef 값을 참조하며 값 변경

  • 결론

    setTimeout/setInterval 에는 useRef!

    리렌더링에 영향을 주지 않는 가변형 값에도 useRef!

Categories: ,

Updated: