React Hotkeys无法获取组件state值的问题求助
问题描述
按下键盘按键时,希望使用useState声明的变量的当前值执行操作,但按键触发的方法始终获取state的默认值(0),即使组件中的test值已经更新。
重现代码
import React from 'react'; import { HotKeys } from 'react-hotkeys'; import { useCallback, useEffect, useState } from 'react'; const keyMap = { MOVE_DOWN: 'a' }; export function App(props) { const [test, setTest] = useState(0); const focusNextRow = useCallback(() => { console.log("test", test); setTest(test => test + 1); console.log("test2", test); }, [test]); useEffect(() => { console.log("TEST IS NOW ", test); }, [test]); const handlers = { MOVE_DOWN: focusNextRow }; return ( <div className='App'> <HotKeys keyMap={keyMap} handlers={handlers}> <div>test</div> </HotKeys> </div> ); }
运行现象
每次按下a键,控制台输出test 0、test2 0,但useEffect中能正确打印更新后的test值(如TEST IS NOW 1、TEST IS NOW 2等)。
解决方法
方法1:用useRef保存最新state值
通过useRef创建引用同步最新state,绕过闭包陷阱直接获取当前值:
import React from 'react'; import { HotKeys } from 'react-hotkeys'; import { useCallback, useEffect, useRef, useState } from 'react'; const keyMap = { MOVE_DOWN: 'a' }; export function App(props) { const [test, setTest] = useState(0); const testRef = useRef(test); // 同步state到ref useEffect(() => { testRef.current = test; }, [test]); const focusNextRow = useCallback(() => { // 从ref中获取最新值 console.log("test", testRef.current); setTest(prev => prev + 1); console.log("test2", testRef.current); }, []); useEffect(() => { console.log("TEST IS NOW ", test); }, [test]); const handlers = { MOVE_DOWN: focusNextRow }; return ( <div className='App'> <HotKeys keyMap={keyMap} handlers={handlers}> <div>test</div> </HotKeys> </div> ); }
方法2:确保HotKeys感知handlers变化
让handlers每次渲染都生成新引用,确保HotKeys绑定最新的处理函数:
import React from 'react'; import { HotKeys } from 'react-hotkeys'; import { useCallback, useEffect, useState } from 'react'; const keyMap = { MOVE_DOWN: 'a' }; export function App(props) { const [test, setTest] = useState(0); const focusNextRow = useCallback(() => { console.log("test", test); setTest(prev => prev + 1); console.log("test2", test); }, [test]); useEffect(() => { console.log("TEST IS NOW ", test); }, [test]); // 每次渲染生成新的handlers对象,确保HotKeys拿到最新函数 const handlers = { MOVE_DOWN: focusNextRow }; return ( <div className='App'> <HotKeys keyMap={keyMap} handlers={handlers}> <div>test</div> </HotKeys> </div> ); }
方法3:函数式更新state(仅需更新场景)
如果只是需要依赖最新值更新state,直接用setTest的函数式写法即可,无需直接访问state变量:
const focusNextRow = useCallback(() => { setTest(prev => { console.log("当前test值", prev); return prev + 1; }); }, []);
原因说明
问题核心是闭包陷阱:focusNextRow通过useCallback缓存时,捕获了创建时的test值。若HotKeys未及时更新绑定的handler,就会始终调用旧版本的函数,导致获取的test永远是初始值0。
内容的提问来源于stack exchange,提问作者Piotrek
相关产品推荐
相关产品推荐

