如何在 useEffect 中向 useRef 添加事件侦听器

Sle*_*vin 6 typescript reactjs react-hooks

我正在构建一个自定义钩子,我想在其中向 ref 添加一个事件侦听器,但我不确定如何正确清理,因为listReflistRef.current可能为空:

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]
}
Run Code Online (Sandbox Code Playgroud)

Ven*_*sky 6

编辑:

但我也必须检查listRef返回函数中是否存在,对吗?

是的,您可以做的是将所有内容都包裹在 if 语句中

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

      return () => {
        listRef.current.removeEventListener(...)
      }
    }
  })
Run Code Online (Sandbox Code Playgroud)

如果您不调用addEventListener,则不需要调用removeEventListener,这就是为什么您将所有内容都放在if.


您需要在 return 中传递一个函数,该函数执行您在清理中想要执行的操作。

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]
}
Run Code Online (Sandbox Code Playgroud)

你需要注意的另一件事是,在fooEventListener,...应该是函数的相同引用,这意味着:

你不应该这样做:

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

    return () => {
        listRef.current.removeEventListener(() => console.log('do something'))
    }
  })
Run Code Online (Sandbox Code Playgroud)

你应该这样做:

  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)
    }
  })
Run Code Online (Sandbox Code Playgroud)

  • 这不应被视为正确答案。useEffect 没有依赖项列表,并且将在每次渲染时添加/删除事件侦听器,这是非常错误的。 (4认同)