我有一个包含6个对象的数组,这些对象具有一个uid和其他所有内容。这样一来,我可以重复它们并拥有一些占位符内容,直到准备好将对象添加到数组中为止。选择新对象时,我会设置一个唯一键。但是,即使我设置了唯一键,如果我两次选择相同的对象。似乎更新了重复项上的唯一键(即使唯一键不同)。
在这里查看运行中的代码/应用可能会更容易,问题的一个示例是先单击squirtle然后进行blastoise,然后注意显示的uid。然后再次单击squirtle,由于某种原因,它将用新的squirtles uid更新旧的squirtle,从而导致重复的键错误。 https://codesandbox.io/s/l75m9z1xwq或查看下面的代码。在我可以正常工作之前,Math.random只是占位符。
const initState = {
party: [
{ uid: 0 },
{ uid: 1 },
{ uid: 2 },
{ uid: 3 },
{ uid: 4 },
{ uid: 5 }
]
};
当我单击某些东西时会触发该事件:
handleClick = pokemon => {
// setup a uid, will need a better method than math.random later
pokemon.uid = Math.random();
this.props.addToParty(pokemon);
};
然后调用一个调度程序,该调度程序将触发以下减速器。实际上,这实际上只是检查对象是否没有普通ID,然后用发送过来的有效负载替换内容。它不仅可以执行此操作,还可以某种方式更新具有相同uid的所有先前对象,即使if语句不针对它们运行。
const rootReducer = (state = initState, action) => {
if (action.type === "ADD_POKEMON") {
let foundFirstEmptyPoke = false;
const newArray = state.party.map((pokemon, index) => {
if (typeof pokemon.id === "undefined" && foundFirstEmptyPoke === false) {
foundFirstEmptyPoke = true;
pokemon = action.payload; // set the data to the first object that ios empty
}
// if we get to the last pokemon and it's not empty
if (index === 5 && foundFirstEmptyPoke === false) {
pokemon = action.payload; // replace the last pokemon with the new one
}
return pokemon;
});
return {
party: newArray
};
}
return state;
};
答案 0 :(得分:3)
这里的问题是,当您单击以选择一个神奇宝贝时,您会对从API中检索到的数据进行突变:
handleClick = pokemon => {
pokemon.uid = Math.random(); // HERE
this.props.addToParty(pokemon);
};
您实际上改变了反应状态。您应该做的是克隆您的pokemon数据对象,向刚生成的克隆中添加一个uid,并使用它更新您的redux状态:
handleClick = pokemon => {
this.props.addToParty({
...pokemon,
uid: Math.random()
});
};
这样,就不会保留对实际反应状态的引用。因为这就是您说it updates the old squirtle with the new squirtles uid
时发生的事情。当您尝试添加其他神奇宝贝时,您更新了从API检索到的数据,该数据也从您的第一个神奇宝贝插槽(从您的redux状态)引用。
答案 1 :(得分:1)
在react / redux中,最好不要突变对象:
this.props.addToParty({...pokemon, uid: Math.random()});
答案 2 :(得分:0)
您正在改变状态。在更新之前,请使用扩展语法***
复制状态。
return {
...state,
party: newArray
}