React useReducer的dispatch无限循环问题及单次执行方案问询
解决页面加载时仅触发一次dispatch且避免无限循环的方案
首先得拆解下你之前代码踩坑的原因:
初始代码的问题根源
你用两个依赖value的useEffect直接导致了无限循环:
- 第一个
useEffect里调用setValue(token)更新value,但它的依赖又是value,所以value一变就会再次执行这个钩子,反复触发setValue - 第二个
useEffect依赖value,每次value更新都会跑dispatch,等于跟着第一个钩子一起进入循环
至于你尝试的useCallback写法,是因为语法错误导致dispatch没被调用:const dis = useCallback(() => dispatch, []) 这行返回的是一个返回dispatch的函数,不是dispatch本身。你调用dis({ ... })的时候,其实是把参数传给了外层的空函数,根本没传到dispatch里,自然没效果。
最简正确实现方案
其实完全不需要中间的useState来存token,直接在组件挂载时拿一次token然后dispatch就行。而且useReducer返回的dispatch本身就是稳定的,不会随组件渲染变化,所以直接用空依赖的useEffect就能实现“仅执行一次”的需求:
// component.js const [state, dispatch] = useReducer(yourReducerFunction, initialState); useEffect(() => { // 从URL查询参数中提取token const searchParams = new URLSearchParams(window.location.search); const token = searchParams.get('token'); // 存在token时触发一次dispatch if (token) { dispatch({ type: 'TEST_TYPE', payload: { data: token } }); } }, []); // 空依赖数组保证该钩子仅在页面加载(组件首次挂载)时执行一次
补充说明
- 如果你的应用是单页应用,后续需要监听URL变化(比如路由切换后重新获取token),可以把
window.location.search或者路由库提供的位置状态加入依赖数组;但如果只需要页面首次加载时拿一次,空数组就足够了 dispatch本身是稳定的,哪怕你把它加到依赖数组里也不会有问题,因为它的引用永远不会改变
内容的提问来源于stack exchange,提问作者stepbystep
相关产品推荐
相关产品推荐

