我试图在一个数组中添加一个元素state
并更改另一个数组元素的属性.假设我们有以下state
结构:
{ menuItems: [{ href: '/', active: true }] }
在调度ADD_MENU_ITEM
动作之后,我想最终得到这个state
:
{ menuItems: [{ href: '/new', active: true }, { href: '/', active: false, }] }
我尝试过几种方式在Redux Reducer中管理它:
function reducer(state = {}, action) { switch (action.type) { case ADD_MENU_ITEM: { let menuItems = state.menuItems; let newMenuItem = action.newMenuItem; // First try menuItems[0].active = false; menuItems.unshift(newMenuItem); state = Object.assign({}, state, { menuItems: menuItems }); // Second try menuItems[0].active = false; menuItems.unshift(newMenuItem); state = Object.assign({}, state, {menuItems: Object.assign([], menuItems)}); // Third try menuItems[0].active = false; state = (Object.assign({}, state, { menuItems: [ Object.assign({}, newMenuItem), ...menuItems ] })); // Fourth try menuItems[0].active = false; state = update(state, { menuItems: {$unshift: new Array(newMenuItem)} }); console.log(state); return state; } } }
在第四次尝试中,我使用的是React的Immutability Helpers,但它永远不会奏效.我登录的状态到控制台返回前的状态并正确记录,但得到重新的组件内登录时rendered
,该阵列的MenuItems不添加的第一个项目,虽然active
成员设置为false
.
我能做错什么?
reducer中的状态应该是不可变的,因此不应该修改.还建议尽可能展平您的物体.
在您的场景中,您的初始状态可能是一个数组:
[{ href: '/', active: true }]
在您的reducer中,尝试返回一个全新的数组,如下所示:
function reducer(state = {}, action) { switch (action.type) { case ADD_MENU_ITEM: { return [ action.newMenuItem, ...state.map(item => Object.assign({}, item, { active: false })) ]; } } }
有关Reducer的更多信息,请访问:Redux Reducers文档
文档的有用摘录:
减速机保持纯净非常重要.你应该在减速机内做的事情:
改变其论点;
执行API调用和路由转换等副作用;
调用非纯函数,例如Date.now()或Math.random().
更多信息已添加
在您的reducer和所有四次尝试中,您在返回之前修改现有状态.
这会导致在react-redux
检查您的状态是否已更改时,不会看到任何更改,因为前一个和下一个状态都指向同一个对象.
以下是我所指的行:
第一次尝试:
// This line modifies the existing state. state = Object.assign({}, state, { menuItems: menuItems });
第二次尝试:
// This line modifies the existing state. state = Object.assign({}, state, {menuItems: Object.assign([], menuItems)});
第三次尝试:
// This line modifies the existing state. state = (Object.assign({}, state, { menuItems: [ Object.assign({}, newMenuItem), ...menuItems ] }));
第四次尝试:
// This line modifies the existing state. state = update(state, { menuItems: {$unshift: new Array(newMenuItem)} });