如何在ReactJS Reducer中正确更新Redux状态?

时间:2019-02-11 15:51:25

标签: arrays reactjs redux react-redux

我的Redux数据存储中具有以下结构:

{
    filterData: {
        22421: {
            filterId: 22421,
            selectedFilters: [
                {
                    filterName: 'gender',
                    text: 'Male',
                    value: 'male'
                },
                {
                    filterName: 'gender',
                    text: 'female',
                    value: 'female'
                }
            ] 
        }   
        22422: {
            filterId: 22422,
            selectedFilters: [
                {
                    filterName: 'colour',
                    text: 'Blue',
                    value: 'blue'
                },
                {
                    filterName: 'animal',
                    text: 'sheep',
                    value: 'Sheep'
                }
            ] 
        }   

有人可以指出我要使用正确的方法来更新selectedFilters数组而不直接改变状态吗?即如何为给定的filterId添加/删除selectedFilters数组中的元素?

2 个答案:

答案 0 :(得分:2)

通常通过使用非变异(即返回一个新对象,而不是修改现有对象)操作符和函数来完成此操作:

您必须在通向最终水平的每个级别上进行此操作-进行更改。对于您的情况,如果要更改其中一个对象的selectedFilters,则必须执行以下操作:

// Assuming you're inside a reducer function.
case SOME_ACTION:
  // Returning the new state object, since there's a change inside.
  return {
    // Prepend old values of the state to this new object.
    ...state,

    // Create a new value for the filters property,
    // since—again—there's a change inside.
    filterData: {
      // Once again, copy all the old values of the filters property…
      ...state.filters,

      // … and create a new value for the filter you want to edit.
      // This one will be about removal of the filter.
      22421: {
        // Here we go again with the copy of the previous value.
        ...state.filters[22421],

        // Since it's an array and we want to remove a value,
        // the filter method will work the best.
        selectedFilters: 
          state.filters[22421].selectedFilters.filter(
            // Let's say you're removing a filter by its name and the name
            // that needs to be removed comes from the action's payload.
            selectedFilter => selectedFilter.name !== action.payload
          )
      },
      // This one could be about addition of a new filter.
      22422: {
        ...state.filters[22422],

        // Spread works best for additions. It returns a new array
        // with the old values being placed inside a new one.
        selectedFilters: [
           // You know the drill.
          ...state.filters[22422].selectedFilters,

          // Add this new filter object to the new array of filters.
          {
            filterName: 'SomeName',
            text: 'some text',
            value: action.value // Let's say the value comes form the action.
          }
        ]
      },
    }
  }

此常数“复制旧值”是必需的,以确保保留嵌套对象中的值,因为散布运算符以浅方式复制属性。

const someObj = {a: {b: 10}, c: 20}
const modifiedObj = {...someObj, a: {d: 30}}
// modifiedObj is {a: {d: 30}, c: 20}, instead of
// {a: {b: 10, d: 30}, c: 20} if spread created a deep copy.

您可以看到,这有点平凡。解决该问题的一种方法是创建某种嵌套的reducers函数,这些函数将在该州的不同树上工作。但是,有时最好不要重新发明工具,而应使用已经解决这些问题的工具。像Immutable.js

答案 1 :(得分:1)

如果您想使用专用的库来管理不可变状态(如另一个答案中所建议的那样),请查看Immer

我发现该库比Immutable.js更简单(而且包的大小也会更小)