React搭配Redux使用useDispatch触发无限重渲染及action报错原因求解
两类React+Redux报错的原因及修复方案
1. 无限重渲染报错(Error: Too many re-renders. React limits the number of renders to prevent an infinite loop)
产生原因
你将dispatch调用直接写在了组件的顶层执行逻辑中:
- 组件每次渲染都会执行顶层的
dispatch语句,触发Redux store数据更新 - store更新后,
useSelector监听到数据变化,会触发当前组件重新渲染 - 重新渲染又会再次执行
dispatch,形成「渲染→dispatch→更新store→渲染」的无限循环
单独保留useSelector逻辑时没有触发store更新的操作,所以不会触发循环。
修复方案
将dispatch调用包裹在useEffect副作用钩子中,控制触发时机,比如仅在组件首次挂载时执行:
import { useEffect } from 'react' var dispatch = useDispatch() var phone = useSelector(store => store.phone) useEffect(() => { const phoneId = window.location.href.split('/').splice(-1) dispatch(phonePagePhone(phoneId)) // 依赖项仅在变化时才会重新触发副作用,dispatch本身引用稳定,无需额外处理 }, [dispatch])
如果路由中的phone参数会动态变化,可以将提取的phoneId也加入依赖项,实现参数变化时自动重新拉取数据。
2. Redux Action类型报错(Actions must be plain objects. Use custom middleware for async actions)
产生原因
Redux原生仅支持接收普通JS对象类型的action,这个报错说明你调用的phonePagePhone action creator返回值不是普通对象,通常是两种情况:
phonePagePhone包含异步逻辑(比如接口请求),返回了Promise、异步函数等非普通对象类型,但项目没有配置对应的Redux异步中间件phonePagePhone代码存在书写错误,没有正确返回action对象
修复方案
- 先确认你的异步逻辑处理方案,最常用的是
redux-thunk中间件,首先检查store创建时是否已经注册了中间件:
// store配置文件示例 import { createStore, applyMiddleware } from 'redux' import thunk from 'redux-thunk' import rootReducer from './reducers' // 必须将thunk加入中间件列表,才能支持返回函数的action creator const store = createStore(rootReducer, applyMiddleware(thunk))
- 检查
phonePagePhone的书写是否符合异步action规范,如果用redux-thunk,异步action creator需要返回一个接收dispatch作为参数的函数:
// 错误写法:直接执行异步逻辑,没有返回函数/普通对象 const phonePagePhone = (phoneId) => { axios.get(`/api/phone/${phoneId}`).then(res => { return { type: 'SET_PHONE', payload: res.data } }) } // 正确写法:返回一个函数,内部执行异步逻辑后调用dispatch const phonePagePhone = (phoneId) => async (dispatch) => { const res = await axios.get(`/api/phone/${phoneId}`) dispatch({ type: 'SET_PHONE', payload: res.data }) }
如果你的逻辑是同步的,直接检查action creator是否正确返回了带type字段的普通对象即可。
内容的提问来源于stack exchange,提问作者Tuzi
相关产品推荐
相关产品推荐

