React에서 eventListeners를 (실제로) 제거하는 방법

예를 들어 사용자 상호 작용을 추적해야 하는 경우가 있습니다. 스크롤 또는 창 크기 변경과 같은 이벤트. 이 경우 eventListener/window/document 등에 body를 추가합니다.

eventListener로 작업할 때 구성 요소가 더 이상 필요하지 않거나 마운트 해제되는 경우 항상 정리에 주의해야 합니다.

마운트 및 마운트 해제



일반적이고 간단한 사용 사례는 초기 탑재 후에 수신기를 추가하고 구성 요소가 탑재 해제될 때 수신기를 제거하는 것입니다. 이것은 useEffect 후크를 사용하여 수행할 수 있습니다.

예시:

  const onKeyDown = (event) => { console.log(event) }

  useEffect(() => {
    window.addEventListener('keydown', onKeyDown)

    return () => { window.removeEventListener('keydown', onKeyDown) }
  }, [])



❗️[]를 호출할 때 두 번째 매개변수useEffect를 잊지 마세요. 그렇지 않으면 모든 렌더링에서 실행됩니다.

상태 변경 또는 속성 변경



위의 예에서 완벽하게 작동하는 것은 상태 또는 소품 변경에 따라 리스너를 추가하고 제거할 때 작동하지 않습니다(배워야 했기 때문에).

예시:

  // ⚠️ This will not work!
  const [isVisible, setVisibility] = useState(false)

  const onKeyDown = (event) => { console.log(event) }

  handleToggle((isVisible) => {
    if (isVisible) window.addEventListener('keydown', onKeyDown)
    else window.removeEventListener('keydown', onKeyDown)
  })

  return (
    <button onClick={() => setVisibility(!isVisible)}>Click me!</button>
  )


버튼을 두 번 클릭한 후 eventListner를 제거해야 합니다. 그러나 그것은 일어날 일이 아닙니다.

하지만 왜?
removeEventListener(event, callback) 함수는 주어진 콜백과 addEventListener()에 전달된 콜백 사이의 동등성 검사를 내부적으로 수행합니다. 이 검사가 true를 반환하지 않으면 수신기가 창에서 제거되지 않습니다.

그러나 addEventListener()removeEventListener()에 정확히 동일한 함수를 전달합니다! 🤯

글쎄,별로.
React는 상태가 변경될 때마다 구성 요소를 새로 렌더링하므로 각 렌더링 내에서 new 함수onKeyDown()도 할당합니다. 이것이 평등 검사가 성공하지 못하는 이유입니다.

해결책



React는 useCallback()이라는 멋진 Hook을 제공합니다. 이를 통해 함수를 메모할 수 있으며 동등성 검사가 성공할 것입니다.

예시

  const [isVisible, setVisibility] = useState(false)

  const onKeyDown = useCallback((event) => { console.log(event) }, [])

  handleToggle((isVisible) => {
    if (isVisible) window.addEventListener('keydown', onKeyDown)
    else window.removeEventListener('keydown', onKeyDown)
  })

  return (
    <button onClick={() => setVisibility(!isVisible)}>Click me!</button>
  )


❗️다시: []를 호출할 때 두 번째 매개변수useCallback()를 잊지 마세요. 콜백이 변경되어야 하는 시기를 제어하기 위해 여기에 종속성 배열을 전달할 수 있습니다. 그러나 그것은 우리의 경우에 필요한 것이 아닙니다.



피드백, 제안 또는 아이디어가 있으면 이 블로그 게시물에 자유롭게 댓글을 달아주세요!

좋은 웹페이지 즐겨찾기