反应:在useEffect挂钩内部调用

时间:2019-08-22 20:55:06

标签: javascript reactjs addeventlistener

如何在useEffect()挂钩中添加事件监听器?

我正在使用useRef()定位nav元素,然后选择所有链接后代。然后,我尝试向这些链接元素添加事件侦听器,但出现错误。

这是我的组件代码的一部分:

let navRef = useRef();

useEffect(() => {
    let links = sideDrawerRef.current.querySelectorAll('ul li a');

    links.addEventListener('click', () => {
      console.log('hay');
    });
  });

<nav ref={navRef} >
  <ul>
    <li><a href="#">Link A</a></li>
    <li><a href="#">Link B</a></li>
  </ul>
</nav>

我遇到以下错误:

  

links.addEventListener不是函数

1 个答案:

答案 0 :(得分:3)

与其添加事件处理程序,不如考虑通过onClick道具将事件绑定委托给React。

这样做可以简化组件的实现:

let navRef = useRef();

const onClickLink = () => {
    console.log('hay');
}

<nav ref={navRef} >
  <ul>
    <li><a href="#" onClick={onClickLink}>Link A</a></li>
    <li><a href="#" onClick={onClickLink}>Link B</a></li>
  </ul>
</nav>

还要在当前代码上添加一些注释,以解释一些问题;

querySelectorAll()方法returns a NodeList。要将点击事件处理程序添加到所有选定的节点,必须迭代每个节点并一次添加事件侦听器:

let links = someAnscestor.querySelectorAll('ul li a');
for(const link of links) {
    /* Add click to currently iterated link node in NodeList result */
    link.addEventListener('click', () => {
      console.log('hay');
    });    
}

此外,此处使用useEffect()的方式将导致每次渲染组件时都运行效果。 Adding [] as the second argument to useEffect()将使效果回调在启动时运行一次,这将更适合此处:

useEffect(() => {
    console.log("I only run when the component first mounts");

    return () => {
        console.log("I run when the component is unmounted");
    }    
}, []); // <-- [] causes effect to run once