使用 React Hooks 设置状态,在什么情况下我必须传递一个函数来设置状态?

With react hooks set state, in what cases I have to pass a function to set state?

这是我的代码:

function Tiker() {
  var [count, setCount] = useState(0);

  useEffect(() => {
    var timerID = setInterval(_=>
      setCount(count=>count+1)//setCount(count+1) wont work
    , 1000);

    return function cleanup() {
      clearInterval(timerID);
    };
  }, []);
  return <div>
      this is ticker   
      <button onClick={() => 
        setCount(count + 1)//setCount(count+1) does work
      }>up </button>
      {count}
      </div>
}

通过反复试验,我发现如果我在 setinterval 回调中使用 setCount,我必须将回调传递给设置状态,而不仅仅是值。

如果我从 onclick 调用,情况就不是这样了。

这是为什么?

问题是useEffect

的第二个参数
useEffect(() => {
    var timerID = setInterval(_=>
        setCount(count=>count+1)//setCount(count+1) wont work
    , 1000);

    return function cleanup() {
        clearInterval(timerID);
    };
}, []);

它是一个空数组([])。它为钩子定义了 list of dependencies 。因为它是空的,这意味着钩子不依赖于状态或道具的任何值。所以 count 变量在 useEffect 的第一次调用时被消耗掉并且比保持陈旧。

要更正此问题,您应该完全删除 useEffect 的第二个参数或使数组包含 [count].

回调正在工作,因为它接收先前的计数值作为第一个参数。

所以正确的代码看起来像

function Tiker() {
    var [count, setCount] = useState(0);

    useEffect(() => {
        var timerID = setInterval(_=>
            setCount(count + 1)
        , 1000);

        return function cleanup() {
            clearInterval(timerID);
        };
    }, [count]);  // Put variable that useHook depends on

    return <div>
        this is ticker   
        <button onClick={() => 
            setCount(count + 1) //setCount(count+1) does work
        }>up </button>
        {count}
    </div>
}

看来使用回调是从 setInterval 调用时更改状态的最简单方法。从上面的 Frodor 评论和 https://overreacted.io/making-setinterval-declarative-with-react-hooks/

可以看出