带有回调的React useState(附代码示例)

1,280 阅读2分钟

如果你已经开始为你的应用程序使用React的useState钩子,你可能缺少一个回调函数,因为只有初始状态可以被传递给钩子。在React类组件中,setState方法提供了一个可选的第二个参数来传递一个回调函数。然而,这个第二个参数对于React的useState钩子是不可用的。如果你正在从React类组件转移到函数组件,这可能是你关心的一个问题。在本教程中,我想向你解释如何实现它。

注意:如果你只是在寻找一个开箱即用的解决方案,可以看看这个带有回调函数的自定义useState钩。这就是你在本教程中要实现的东西。我也会在下面展示它是如何工作的。

React useState回调

在带有钩子React功能组件中,你可以使用useEffect钩子为任何东西实现回调函数。例如,如果你想有一个状态变化的回调函数,你可以让useEffect钩子依赖于这个状态。

import React from 'react';

const App = () => {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    if (count > 1) {
      console.log('Threshold of over 1 reached.');
    } else {
      console.log('No threshold reached.');
    }
  }, [count]);

  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>{count}</p>

      <button type="button" onClick={handleClick}>
        Increase
      </button>
    </div>
  );
};

export default App;

你传递给useEffect钩子的函数是你的回调函数,它在提供的状态从useState钩子的第二个参数变化后运行。如果你在这个回调函数中执行的变化应该反映在你的组件的渲染输出中,你可能想使用useLayoutEffect而不是useEffect

如果你正在寻找一个开箱即用的解决方案,可以看看这个自定义钩子,它的工作原理和useState一样,但接受第二个参数作为回调函数。

import React from 'react';

import useStateWithCallback from 'use-state-with-callback';

const App = () => {
  const [count, setCount] = useStateWithCallback(0, count => {
    if (count > 1) {
      console.log('Threshold of over 1 reached.');
    } else {
      console.log('No threshold reached.');
    }
  });

  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>{count}</p>

      <button type="button" onClick={handleClick}>
        Increase
      </button>
    </div>
  );
};

export default App;

这个自定义的钩子可以通过npm install use-state-with-callback 来安装。最后,React团队决定有意识地反对为useState提供回调函数的第二个参数,因为可以用useEffect或useLayoutEffect代替。然而,如果你很懒,你可以使用自定义钩子来获得与React类组件的setState相同的效果。

带有懒人回调功能的React useState

如果你想有一个懒惰的可执行函数来代替,你也可以使用该库。

import React from 'react';
import { useStateWithCallbackLazy } from 'use-state-with-callback';

const App = () => {
  const [count, setCount] = useStateWithCallbackLazy(0);

  const handleClick = () => {
    setCount(count + 1, (currentCount) => {
      if (currentCount > 1) {
        console.log('Threshold of over 1 reached.');
      } else {
        console.log('No threshold reached.');
      }
    });
  };

  return (
    <div>
      <p>{count}</p>

      <button type="button" onClick={handleClick}>
        Increase
      </button>
    </div>
  );
};

export default App;

这样,你可以决定何时使用回调函数的第二个参数,你可以为每种情况决定回调函数应该具体做什么。