简体   繁体   English

useEffect() 没有清理功能

[英]useEffect() without a cleanup function

it says that : "Each time that our component renders, our effect is called, adding another event listener. With just a few clicks and re-renders, we have attached a lot of event listeners to the DOM! We need to clean up after ourselves!".它说:“每次我们的组件渲染时,我们的效果都会被调用,添加另一个事件侦听器。只需点击几下并重新渲染,我们就将很多事件侦听器附加到 DOM!我们需要在之后清理我们自己!”。

so for every click the count goes from 1 to 3 to 7 instead of incrementing by 1. I don't understand how does so many event listeners got attached and how is this effecting the total count?所以对于每次点击,计数从 1 到 3 到 7,而不是增加 1。我不明白如何附加这么多事件侦听器以及这如何影响总计数?

import React, { useState, useEffect } from 'react';

export default function Counter() {
  const [clickCount, setClickCount] = useState(0);

  const increment = () => {
    setClickCount(prev => prev + 1);
  };

  useEffect(() => {
    document.addEventListener('mousedown', increment);

  })

  return (
      <h1>Document Clicks: {clickCount}</h1>
  );
}

You're adding a listener to the document itself , so you need to remove it when component is unmounted.您正在向文档本身添加一个侦听器,因此在卸载组件时需要将其删除。

And you need to add an empty dependency array to not add a new listener on each rerender并且您需要添加一个空的依赖数组,以免在每次重新渲染时添加新的侦听器

And you either need to wrap increment in a useCallback or use a different increment function in the useEffect :你要么需要换incrementuseCallback或使用不同的增量函数useEffect

import React, { useState, useEffect } from 'react';

export default function Counter() {
  const [clickCount, setClickCount] = useState(0);

  const increment = useCallback(() => {
    setClickCount(prev => prev + 1);
  }, [setClickCount]);

  useEffect(() => {
    document.addEventListener('mousedown', increment);

    return () => document.removeEventListener('mousedown', increment);
  }, [])

  return (
      <h1>Document Clicks: {clickCount}</h1>
  );
}

Without using an array of dependencies, every change will trigger your useEffect to run again.如果不使用依赖项数组,每次更改都会触发useEffect再次运行。

So every re-render, every changing state will cause you to create another eventListener .因此,每次重新渲染、每次更改状态都会导致您创建另一个eventListener

Let's talk about variant useEffect :让我们谈谈变体useEffect

useEffect(() => {
  // invoking on every re-render
})
useEffect(() => {
  // invoking on component did mount (once)
}, [])
useEffect(() => {
  // invoking on component did mount and with every change on counter
}, [counter])

Also, you need to remove your eventLinstener on the component unmount:此外,您需要在组件卸载时删除eventLinstener

 useEffect(() => {
    document.addEventListener('mousedown', increment);

    return () => document.removeEventListener('mousedown', increment);

  }, [])

Optional可选的

As mentioned with Samathingamajig in the answers, you can use an optimized way to define your increment function with useCallback .正如答案中 Samathingamajig 所提到的,您可以使用优化的方式来定义useCallbackincrement函数。

With the current implementation, your increment method will be re-defined every time (with every change and re-render) but using useCallback it will be redefined only when the useCallback 's array of dependencies got changes.对于当前的实现,您的increment方法每次都会重新定义(每次更改和重新渲染),但是使用useCallback只会在useCallback的依赖项数组发生更改时重新定义它。

import React, {useEffect, useCallback} from 'react';

// rest of the codes ...

  const increment = useCallback(() => {
    setClickCount(prevState => prevState + 1);
  }, [setClickCount]);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM