在 Redux 中改变状态

Changing state in Redux

我正在尝试向 state 中的数组添加一个元素并更改另一个数组元素的 属性。假设我们有以下 state 结构:

{
  menuItems: [{
    href: '/',
    active: true
  }]
}

发送 ADD_MENU_ITEM 操作后,我想以这个 state:

结束
{
  menuItems: [{
    href: '/new',
    active: true
  }, {
    href: '/',
    active: false,
  }]
}

我已经尝试在 Redux reducers 中以多种方式管理它:

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 }))
      ];
    }
  }
}

可以在此处找到有关减速器的更多信息:Redux Reducers Documentation

文档中的有用摘录:

It’s very important that the reducer stays pure. Things you should never do inside a reducer:

  • Mutate its arguments;
  • Perform side effects like API calls and routing transitions;
  • Calling non-pure functions, e.g. Date.now() or Math.random().

添加了更多信息

在你的减速器中,对于所有四次尝试,你在返回之前修改现有状态。

这会导致 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)}
  });