无限循环 React 钩子

IT技术 javascript reactjs react-hooks
2021-04-26 23:30:59

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

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>
}
2个回答

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

您可以改为提供一个函数作为setVal. 此函数获取当前值val作为参数并返回新值。这种方式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>

上面的代码显示了如何摆脱无限循环并且对实验很有value,但大部分都不是必需的。您可以改为编写相同的功能:

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>