React钩子useEffect无限循环运行的问题

71
我正在尝试使用新的React HooksuseEffect API,但它似乎会一直运行,形成无限循环!我只想让useEffect中的回调函数运行一次。以下是我的参考代码:

点击“运行代码片段”查看控制台中是否无限打印“Run useEffect”字符串。

function Counter() {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    console.log('Run useEffect');
    setCount(100);
  });

  return (
    <div>
      <p>Count: {count}</p>
    </div>
  );
}

ReactDOM.render(<Counter />, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>

2个回答

130
这是因为每次渲染后都会触发useEffect,在函数组件中的例子中就是对Counter()函数的调用。当你在useEffect中调用由useState返回的setX函数时,React将再次渲染该组件,并再次运行useEffect,从而导致了无限循环:

Counter()useEffect()setCount()Counter()useEffect() → ... (loop)

如果想让useEffect只运行一次,请将空数组[]作为第二个参数传递,如下所示。

第二个参数的意图是告诉React仅在数组参数中的任何值更改时才运行useEffect:

useEffect(() => {
  setCount(100);
}, [count]); // Only re-run the effect if count changes
你可以将任意数量的值传递到数组中,当其中任何一个值发生更改时,useEffect才会运行。通过传递空数组,我们告诉React不要跟踪任何更改,只运行一次,有效地模拟componentDidMount

function Counter() {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    console.log('Run useEffect');
    setCount(100);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
    </div>
  );
}

ReactDOM.render(<Counter />, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>

阅读更多关于useEffect的内容。


11
这是解决方案,但如果你正在使用react-hooks ESLint插件,它会被exhaustive-deps规则标记出来。正确的解决方案似乎是使用useCallback钩子,更多讨论请参见此处:https://github.com/facebook/react/issues/14920#issuecomment-471070149 - Daniel Cooke

3

你遇到了无限循环的问题,因为在编写 useEffect 时没有提供依赖项。

为了避免使用 useEffect 钩子时出现无限循环,请确保提供一个包含所有 effect 所依赖变量的依赖项数组

例如,如果你只想让effect 在组件挂载时运行一次,可以像这样传递一个空的依赖项数组:

useEffect(() => {
   // effect code here
}, [])

如果你想让效果在特定变量改变时运行,你可以将该变量包含在依赖数组中:
const [count, setCount] = useState(0);

useEffect(() => {
  // effect code here
}, [count])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接