仅使用Redux(未用react-redux)时useEffect中dispatch后cards报map错误
问题排查与修复
核心问题:reducer缺少默认返回值,导致store初始化失败
Redux要求reducer在未匹配到对应action类型时,必须返回传入的原有state,否则会把store的全局state直接覆盖为undefined。
你的reducer逻辑里,default分支只写了break,函数执行结束后没有返回值,最终返回undefined。
而createStore初始化时,会自动dispatch一个内部的初始化action,这个action永远匹配不上SET_CARDS类型,会直接走入default分支,把你一开始传入的预定义state(带空cards数组的那个对象)直接覆盖为undefined。
这就能解释你观察到的差异:
- 在store.js里手动dispatch动作时,reducer拿到的当前state是
undefined,执行{...undefined, cards: 生成的卡牌数组}是合法的JS语法,最终返回一个带cards属性的新对象,所以这时候取cards能正常拿到数组,看起来功能正常 - 但组件首次渲染时,
store.getState()本身就是undefined,你写的store.getState().cards?.map的可选链只做了cards存在性的判断,挡不住“读取undefined对象上的cards属性”的报错,最终抛出无法对cards调用map的错误。
修复代码:
const reducer = (state, action) => { switch (action.type) { case "SET_CARDS": return { ...state, cards: action.payload.initCards(), }; default: // 未匹配的action直接返回原state,不能让reducer返回undefined return state; } };
次要问题:可选链的保护逻辑位置错误
你目前的可选链写法:
{store.getState().cards?.map((card) => <div>{card}</div>)}
只判断了cards字段是否存在,没判断store.getState()本身是否有效,安全的写法应该把可选链提前到读取getState结果的位置:
{store.getState()?.cards?.map((card) => <div>{card}</div>)}
额外规范提醒
- 按照Redux的设计规范,action的payload应该存放可序列化的纯数据,不建议把
initCards这种带逻辑的生成函数存在action对象里。你可以提前把卡牌数组生成好,直接把数组作为payload传入action,避免把非序列化数据存在store的动作流里。 - 现在
setCards对象是写在Game组件函数体内的,虽然空依赖的useEffect只会在首次渲染时执行一次dispatch,不会直接导致功能失效,但每次组件重渲染都会重新创建这个大对象,可以把它挪到组件外部定义,减少不必要的内存消耗。
内容的提问来源于stack exchange,提问作者morh
相关产品推荐
相关产品推荐

