改变减速器上的状态对象
Changing state object on reducer
我正在尝试更改我的减速器上的一个对象,正如我在其他地方读到的那样,Object.assign 在该对象上创建了一个新副本,但元素是相同的 (),所以我不断收到
Invariant violation, state mutation was detected inside dispatch
尝试时
let newTravelersObject = Object.assign({}, state.travelers);
我想如果我有一个数组,我可以使用 map,我也尝试过使用 loadhash _.mapValues 但得到同样的错误。
另一种解决方案是重组我的代码以使用数组而不是对象,但我认为我不应该这样做,我拒绝相信它无法完成
state.travelers 对象
{
"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
});
class 的构造函数,其中状态为
class TravelersPage extends React.Component {
constructor(props, context){
super(props, context);
this.state = {
travelers: Object.assign({}, props.travelers),
currentTravelerId: null,
loading: true,
...
};
您正在改变嵌套对象,例如 results[id].enemies.push
。
请注意 .findIndex
将 return 是浅拷贝而不是深拷贝。
我建议重新考虑这里的模式并考虑更简洁和可读的流程。
只是 return 一个新对象,但映射到结果数组和 return 不具有相同 traveler_id
的旅行者,当你找到相关的 traveler
return一个新对象并覆盖它的enemies
数组,return一个具有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>
我认为你应该添加更多的 reducer,我的经验是为每个实体创建一个 reducer(travelersReducer、travelerReducer、enemiesReducer、enemyReducer...)。
我实际上 不久前还包含了一个创建更多 reducer 的示例。
请注意,我没有使用 Object.assign
,而是使用了 object spread feature which is a proposal but in stage 3。
我正在尝试更改我的减速器上的一个对象,正如我在其他地方读到的那样,Object.assign 在该对象上创建了一个新副本,但元素是相同的 (
Invariant violation, state mutation was detected inside dispatch
尝试时
let newTravelersObject = Object.assign({}, state.travelers);
我想如果我有一个数组,我可以使用 map,我也尝试过使用 loadhash _.mapValues 但得到同样的错误。
另一种解决方案是重组我的代码以使用数组而不是对象,但我认为我不应该这样做,我拒绝相信它无法完成
state.travelers 对象
{
"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
});
class 的构造函数,其中状态为
class TravelersPage extends React.Component {
constructor(props, context){
super(props, context);
this.state = {
travelers: Object.assign({}, props.travelers),
currentTravelerId: null,
loading: true,
...
};
您正在改变嵌套对象,例如 results[id].enemies.push
。
请注意 .findIndex
将 return 是浅拷贝而不是深拷贝。
我建议重新考虑这里的模式并考虑更简洁和可读的流程。
只是 return 一个新对象,但映射到结果数组和 return 不具有相同 traveler_id
的旅行者,当你找到相关的 traveler
return一个新对象并覆盖它的enemies
数组,return一个具有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>
我认为你应该添加更多的 reducer,我的经验是为每个实体创建一个 reducer(travelersReducer、travelerReducer、enemiesReducer、enemyReducer...)。
我实际上
请注意,我没有使用 Object.assign
,而是使用了 object spread feature which is a proposal but in stage 3。