无限循环 React 钩子

Infinite loop React hooks

我不明白为什么我会进入无限循环 useClick 我看到我使用 setVal 更改了 useEffect 中的状态值,但是 useEffect 应该只在 onClick 上工作,因为在第二个参数中指定。我认为这是因为我传递的参数 onClick 被记忆但没有调用回调(我使用 console.log('go set')[=11= 检查过]

function useClick(onClick, setVal, val) {
  React.useEffect(() => {
    console.log('Click');
    setVal(val + 1);
  }, [onClick]);
}

const Home = () => {
  const [val, setVal] = React.useState(0);
  const incrementOnClick = React.useCallback(() => {
    console.log('go set');
    setVal(val + 1);
  } , [setVal, val]);
  useClick(incrementOnClick, setVal, val);
  return <div>
    <div>{val}</div>
    <button onClick={incrementOnClick}>Click me</button>
 </div>
}

valsetVal 将在每次渲染时发生变化,这反过来又会导致 incrementOnClick 成为新的函数引用,并且您的 useClick 效果将始终是调用。

您可以将一个函数作为 setVal 的第一个参数。此函数获取当前 val 作为参数,并获取 returns 新值。这样 incrementOnClick 将始终是相同的函数。

const { useEffect, useState, useCallback } = React;

function useClick(onClick, setVal, val) {
  useEffect(() => {
    console.log("Click");
    setVal(val + 1);
  }, [onClick]);
}

const Home = () => {
  const [val, setVal] = useState(0);
  const incrementOnClick = useCallback(() => {
    console.log("go set");
    setVal(val => val + 1);
  }, []);

  useClick(incrementOnClick, setVal, val);

  return (
    <div>
      <div>{val}</div>
      <button onClick={incrementOnClick}>Click me</button>
    </div>
  );
};

ReactDOM.render(<Home />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

上面的代码展示了如何摆脱无限循环并且可能对实验有价值,但其中大部分都不是必需的。您可以像这样编写相同的功能:

const { useState } = React;

const Home = () => {
  const [val, setVal] = useState(1);
  
  return (
    <div>
      <div>{val}</div>
      <button onClick={() => setVal(val + 1)}>Click me</button>
    </div>
  );
};

ReactDOM.render(<Home />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

看看你想做什么,我相信你错过了 Hooks & React 最有用的功能之一,那就是组合。

这是您所做工作的示例,但只是创建另一个名为 <IncrementButton/> 的组件,对我来说,这只会让代码更容易理解/调试。自定义挂钩很棒,但我认为这样做是错误的工具..

const { useEffect, useState } = React;

const IncrementButton = props => {
  const {val, setVal, children} = props;
  return <button
    onClick={() => setVal(val + 1)}
  >{children}</button>;
}

const Home = () => {
  const [val, setVal] = useState(0);
  return (
    <div>
      <div>{val}</div>
      <IncrementButton val={val} setVal={setVal}>
        Click me
      </IncrementButton>
    </div>
  );
};

ReactDOM.render(<Home />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>