useState改变值之后立刻获取最新的状态

10,717 阅读1分钟

基本案例

function App() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(2);
    func(); // 点击后打印 0
  };

  const func = () => {
    console.log(count);
  };

  return (
    <div className="App">
      <button onClick={handleClick}>点击</button>
    </div>
  );
}

当我们点击按钮时,控制台打印的还是上一次的值0,而不是最新的2

因为在react合成事件中改变状态是异步的,出于减少render次数,react会收集所有状态变更,然后比对优化,最后做一次变更,在代码中可以看出,func的调用和setCount在同一个宏任务中,这是react还没有render,所以直接使用count获取的肯定是上一次闭包里的值0

有的人可能会说,直接将最新的值当作参数传递给func不就行了吗,对,这也是一种解决办法,但是有时不只是一个状态,可能要传递的参数很多,再有也是出于对react-hooks的深入研究,所以我选择通过自定义hooks实现在useState改变值之后立刻获取到最新的值,我们先看下实现的效果,代码变更如下:

function App() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setstate(2);
    func(); // 打印 2
  };
  /** 将func的方法传递给useSyncCallback然后返回一个新的函数 */
  const func = useSyncCallback(() => {
    console.log(count);
  });

  return (
    <div className="App">
       <button onClick={handleClick}>点击</button>
    </div>
  );
}

export default App;

如何实现useSyncCallback?

import { useEffect, useState, useCallback } from 'react';

const useSyncCallback = callback => {
    const [proxyState, setProxyState] = useState({ current: false });

    const Func = useCallback(() => {
        setProxyState({ current: true });
    }, [proxyState])

    useEffect(() => {
        if (proxyState.current === true) setProxyState({ current: false });
    }, [proxyState])

    useEffect(() => {
        proxyState.current && callback();
    })

    return Func
}

export default useSyncCallback;