React-Redux Reducer单元测试:正确返回值咨询
嘿,我能理解你在写单元测试时碰到这个返回值不匹配的困惑——明明预期是简洁的{"isConnected": false},结果拿到了一个混合了数组键和对象属性的奇怪结构,这大概率是因为你的reducer状态结构前后不一致导致的。我来给你拆解清楚:
核心原则:Reducer返回值必须和初始状态结构一致
Redux里的reducer本质是纯函数,它接收当前状态(state)和动作(action),返回新的状态值。这个状态可以是对象、数组、字符串、数字任何类型,但有个硬规则:你返回的状态结构必须和你定义的初始状态结构完全匹配。
比如:
- 如果初始状态是
{ isConnected: false }(对象类型),那所有分支的返回值都得是同结构的对象; - 如果初始状态是
[{ isConnected: true }](数组类型),那reducer就该始终返回数组。
你的问题根源:状态结构被意外混淆了
你实际收到的{"0": {"isConnected": true}, "isConnected": false},这说明你的reducer在某个分支里错误地把对象状态当成数组来处理了。比如可能不小心写了类似数组拼接的代码:
// 错误示例:把对象状态当成数组来拼接 return [...state, { isConnected: false }];
因为数组在JS里本质是带数字键的对象,这么写就会把原来的对象属性(isConnected)和数组的索引键("0")混在一起,就出现了你看到的奇怪结构。
正确的写法示例(针对你的预期)
既然你预期返回{"isConnected": false},说明你的初始状态应该是对象类型。那正确的reducer应该这样写:
// 初始状态是对象 const initialState = { isConnected: true }; const connectionReducer = (state = initialState, action) => { switch (action.type) { case 'DISCONNECT': // 用展开运算符复制旧状态,再覆盖需要更新的属性——遵循不可变性 return { ...state, isConnected: false }; case 'CONNECT': return { ...state, isConnected: true }; // 别忘了default分支返回原状态 default: return state; } };
这样处理DISCONNECT动作时,返回的就是你预期的{ isConnected: false },单元测试就能匹配上了。
什么时候用数组类型的状态?
如果你的状态是一组同类型的数据(比如多个连接实例),那用数组才合理。比如初始状态是[{ id: 1, isConnected: true }, { id: 2, isConnected: false }],这时候reducer里就会用map、filter或者展开运算符来处理数组,返回新的数组状态。
总结一下:没有“必须返回对象或数组”的强制要求,关键是保持状态结构的一致性,并且始终遵守Redux的不可变性原则——永远不要直接修改原state,要返回新的状态副本。
内容的提问来源于stack exchange,提问作者Oak

