React.js中短时间内点击与mouseLeave事件间如何获取正确状态
问题原因
点击按钮触发onClick修改visible为true后立即移开鼠标,控制台打印的还是false,核心原因是:
- React的state更新是异步批量处理的,不会立即生效;
- 函数组件的事件回调会捕获当前渲染周期的state快照——
onMouseLeave回调创建时绑定的是初始渲染的visible值(false),组件重新渲染前触发该回调,只会读取旧的state值。
解决方法
下面提供几种实用的解决方案:
方法1:用useRef同步最新state
通过useRef创建一个可变容器,实时同步state的最新值,这样在mouseLeave回调里可以直接读取到最新的state:
const App = (props) => { const [visible, setVisible] = React.useState(false); const visibleRef = React.useRef(visible); // 每次state更新时同步到ref React.useEffect(() => { visibleRef.current = visible; }, [visible]); return ( <button onClick={() => setVisible(true)} onMouseLeave={() => console.log(visibleRef.current)} > test </button> ); }; ReactDOM.render(<App />, document.getElementById("root"));
方法2:通过setState的函数式回调获取当前state
如果只是需要在mouseLeave时获取最新state,可以借助setVisible的函数式调用,在回调参数里拿到当前最新的state值(这种方式不需要额外创建ref):
const App = (props) => { const [visible, setVisible] = React.useState(false); return ( <button onClick={() => setVisible(true)} onMouseLeave={() => { // 用函数式更新获取当前state,不修改state值 setVisible(current => { console.log(current); return current; }); }} > test </button> ); }; ReactDOM.render(<App />, document.getElementById("root"));
方法3:点击时缓存最新值(单次场景适用)
如果只是针对这次点击操作,可以在onClick里先缓存新的state值,后续直接使用:
const App = (props) => { const [visible, setVisible] = React.useState(false); const latestVisible = React.useRef(false); return ( <button onClick={() => { const newValue = true; latestVisible.current = newValue; setVisible(newValue); }} onMouseLeave={() => console.log(latestVisible.current)} > test </button> ); }; ReactDOM.render(<App />, document.getElementById("root"));
原理补充
函数组件每次渲染都会生成独立的state快照和事件回调,旧回调只会绑定对应渲染周期的state值。而useRef的current属性是可变的,不受渲染周期限制,能始终保存最新的状态,所以可以用来同步获取最新state。
内容的提问来源于stack exchange,提问作者WUSO01
相关产品推荐
相关产品推荐

