Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add an event listener to useRef in useEffect

I'm building a custom hook where I want to add an event listener to a ref, but I'm not sure how to clean up properly, since listRef and listRef.current could be null:

export const myHook: MyHook = () => {
  const listRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    // I can check for the presence of `listRef.current` here ...
    if (listRef && listRef.current) {
      listRef.current.addEventListener(...)
    }

    // ... but what's the right way for the return function?
    return listRef.current.removeEventListener(...)
  })

  return [listRef]
}
like image 631
Slevin Avatar asked Mar 03 '20 18:03

Slevin


1 Answers

Edit:

but I have to check for the presence of listRef in the return function too, right?

Yes, and what you could do is wrap everythinig around the if statement

  useEffect(() => {
    // Everything around if statement
    if (listRef && listRef.current) {
      listRef.current.addEventListener(...)

      return () => {
        listRef.current.removeEventListener(...)
      }
    }
  })

If you don't call addEventListener, you don't need to call removeEventListener, so that is why you put everything inside the if.


You need to pass a function in the return that do what you want to do in the cleanup.

export const myHook: MyHook = () => {
  const listRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    // This is ok
    if (listRef && listRef.current) {
      listRef.current.addEventListener(...)
    }

    // Passing a function that calls your function
    return () => {
        listRef.current.removeEventListener(...)
    }
  })

  return [listRef]
}

Another thing you need to notice is that inside the fooEventListener, the ... should be the same reference of the function, this means:

You shoudn't do this:

  useEffect(() => {
    if (listRef && listRef.current) {
      listRef.current.addEventListener(() => console.log('do something'))
    }

    return () => {
        listRef.current.removeEventListener(() => console.log('do something'))
    }
  })

And you should do :

  useEffect(() => {
    const myFunction = () => console.log('do something')

    if (listRef && listRef.current) {
      // Passing the same reference
      listRef.current.addEventListener(myFunction)
    }

    return () => {
      // Passing the same reference
      listRef.current.removeEventListener(myFunction)
    }
  })
like image 105
Vencovsky Avatar answered Sep 19 '22 10:09

Vencovsky