在reducer上更改状态对象

时间:2017-12-02 17:41:12

标签: reactjs reduce

我正在尝试更改我的reducer上的一个对象,正如我在别处读到的那样,Object.assign在对象上创建了一个新副本,但元素是相同的(https://stackoverflow.com/a/37819614/3808307),所以我不断得到

  

不变违规,在调度内检测到状态突变

尝试时

let newTravelersObject = Object.assign({}, state.travelers);

我想如果我有一个数组,我可以使用map,我也尝试过使用loadhash _.mapValues但是得到了同样的错误。

另一个解决方案是重构我的代码以使用数组而不是对象,但我不认为我应该这样做,我拒绝相信它无法完成

state.travelers object

{
  "results": [
    {"id" : 34,
      "name": "",
      "enemies" : [
        {"profession": "Dentist", "id": 54},
        {"profession": "Police officer", "id": 471}
    },  
    {"id" : 52,
      "name": "Alicia",
      "enemies" : [
        {"profession": "Architect", "id": 61}
    },
    ...
  ],
  "count": 7
}



case types.ADD_ENEMY_SUCCESS:

  let newTraverlersObject = Object.assign({}, state.travelers);     

  let id = _.findIndex(newTraverlersObject.results, ["id", action.enemy.traveler_id]);
  newTraverlersObject.results[id].enemies.push({"id": action.enemy.id, "profession": action.enemy.profession});


  return Object.assign({}, state, {
    travelers: newTravelersObject
  });

state为

的类的构造方法
class TravelersPage extends React.Component {
  constructor(props, context){
    super(props, context);
    this.state = {
      travelers: Object.assign({}, props.travelers),
      currentTravelerId: null,
      loading: true,
      ...
    };

1 个答案:

答案 0 :(得分:2)

您正在改变嵌套对象,例如results[id].enemies.push 请注意,.findIndex将返回浅拷贝而不是深拷贝。

我建议重新考虑这里的模式,并考虑更简洁和可读的流程。

只需返回一个新对象,但映射到结果数组,并返回不具有相同traveler_id的旅行者,当您确实发现相关的traveler返回一个新对象并覆盖enemies数组,返回一个带有ES2015扩展功能的新数组,最后添加新的敌人对象。

这是一个正在运行的例子:



const newItems = {
  "results": [{
    "id": 34,
    "name": "",
    "enemies": [{
      "profession": "Dentist",
      "id": 54
    }, {
      "profession": "Police officer",
      "id": 471
    }]
  }, {
    "id": 52,
    "name": "Alicia",
    "enemies": [{
      "profession": "Architect",
      "id": 61
    }],
  }]
};
const action = {
  type: 'ADD_ENEMY_SUCCESS',
  enemy: {
    id: 999,
    traveler_id: 34,
    profession: 'my new proffesion!!!'
  }
};
const travelersReducer = (state = {}, action) => {
  switch (action.type) {
    case 'ADD_ENEMY_SUCCESS':
      {
        const {
          enemy: {
            id,
            traveler_id,
            profession
          }
        } = action;
        const nextState = {
          ...state,
          results: state.results.map(traveler => {
            if (traveler.id !== traveler_id) return traveler; // this is not out target, return the object as is
            return { // return a new object
              ...traveler,
              enemies: [
                ...traveler.enemies, { // new enemy
                  id,
                  profession,
                }
              ]
            }
          })
        };
        return nextState;
      }
      defualt: return state;
  }
}

console.log(travelersReducer(newItems, action));

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
&#13;
&#13;
&#13;

我认为你应该添加更多减速器,我的经验法则是为每个实体创建一个减速器(旅行者减速器,旅行者减速器,敌人减速器,敌人减速器......)。

我不久前实际上answered a similar question并且包含了创建更多缩减器的示例。

请注意,我没有使用Object.assign,而是使用object spread feature作为提案but in stage 3