如何在useIdleTimer的onIdle回调中获取最新user状态?
解决useIdleTimer回调中无法获取最新user状态的问题
你遇到的是典型的闭包陷阱:useIdleTimer初始化时,handleOnIdle捕获的是组件首次渲染时的user值(也就是null),后续user更新时,这个回调函数的引用没有更新,定时器依然调用旧的回调,所以始终拿不到最新的user。
下面给你两种可行的解决方案:
方案一:用useRef保存最新user引用
通过useRef存储user的最新值,因为ref的.current属性是可变的,不受闭包限制,回调里直接取userRef.current就能拿到最新状态:
const { user } = useTypedSelector((state) => state.auth) const userRef = useRef(user); // 同步user状态到ref useEffect(() => { userRef.current = user; }, [user]); const [isInactiveModalActive, setIsInactiveModalActive] = useState(false) const handleOnIdle = () => { if (userRef.current) { setIsInactiveModalActive(true) } } useIdleTimer({ onIdle: handleOnIdle, timeout: 1000, crossTab: true, debounce: 500, })
方案二:让定时器随user变化重新初始化
用useCallback包裹handleOnIdle,把user作为依赖项,同时给useIdleTimer添加依赖,确保user更新时,定时器会重新初始化并绑定新的回调:
const { user } = useTypedSelector((state) => state.auth) const [isInactiveModalActive, setIsInactiveModalActive] = useState(false) // 每次user变化时生成新的回调 const handleOnIdle = useCallback(() => { user && setIsInactiveModalActive(true) }, [user]); // 依赖handleOnIdle,回调更新时重新创建定时器 useIdleTimer({ onIdle: handleOnIdle, timeout: 1000, crossTab: true, debounce: 500, }, [handleOnIdle]);
两种方案对比
- 方案一不会频繁重新创建定时器,性能更优,适合大部分场景;
- 方案二每次
user变化都会重启定时器,如果你需要在用户登录/登出时重置闲置计时,可以选这种。
内容的提问来源于stack exchange,提问作者nikulas13
相关产品推荐
相关产品推荐

