为什么分配的对象也没有被写入?
Why is the assigned object not being written too?
我有一个反冲状态,它是一个结构如下的对象:
const Proposal = atom({
key: "PROPOSAL",
scopes: [{
assemblies: [{
items: [{}]
}]
}]
})
当 UI 中的项目有更新时,我将通过作用域、程序集和项目的映射来更新原子。当我找到要更新的正确项目时,我会记录当前项目,然后记录更新的项目。这些日志是正确的,因此我可以看到正在更新的值。但是当我到达第三个日志时,它没有显示更新的值。
const [proposal, setProposal] = useRecoilState(Proposal)
const applyUpdatesToProposalObj = useCallback(_.debounce(params => {setProposal(proposal => {
setProposal(proposal => {
let mutable = Object.assign({}, proposal);
for(let i = 0; i < mutable.scopes.length; i++) {
let scope = mutable.scopes[i]
for(let j = 0; j < scope.assemblies.length; j++) {
let assembly = scope.assemblies[j]
for(let k = 0; k < assembly.items.length; k++) {
let item = assembly.items[k]
if(item._id === id) {
console.log('1', item)
item = {
...item,
...params
}
console.log('2', item)
}
}
}
}
console.log('3', mutable)
return mutable
})
}, 350), [])
日志的输出如下所示:
1 { ...item data, taxable: false }
2 { ...item data, taxable: true }
3 { scopes: [{ assemblies: [{ items: [{ ...item data, taxable: false }] }] }] }
我设置了一个沙盒,您可以在其中查看行为 https://codesandbox.io/s/young-dew-w0ick?file=/src/App.js
另一件奇怪的事情是我在提案中有一个名为更改的对象。我为更改对象设置了一个原子并以类似的方式更新它,并且按预期工作。
扩展我们在评论中的小谈话:你必须克隆你想要变异的整个对象树,一路克隆每个级别。这在普通 javascript 中是相当乏味的,所以以牺牲一点性能为代价(这个例子正在沿途更新所有数组),这可以优化为更具可读性:
setProposal((proposal) => {
let mutable = proposal;
console.log("before", mutable);
mutable = {
...mutable,
scopes: mutable.scopes.map((scope) => ({
...scope,
assemblies: scope.assemblies.map((assembly) => ({
...assembly,
items: assembly.items.map((item) => {
if (item.id === id) {
return {
...item,
...params
};
} else {
return item;
}
})
}))
}))
};
console.log("after", mutable);
return mutable;
});
我有一个反冲状态,它是一个结构如下的对象:
const Proposal = atom({
key: "PROPOSAL",
scopes: [{
assemblies: [{
items: [{}]
}]
}]
})
当 UI 中的项目有更新时,我将通过作用域、程序集和项目的映射来更新原子。当我找到要更新的正确项目时,我会记录当前项目,然后记录更新的项目。这些日志是正确的,因此我可以看到正在更新的值。但是当我到达第三个日志时,它没有显示更新的值。
const [proposal, setProposal] = useRecoilState(Proposal)
const applyUpdatesToProposalObj = useCallback(_.debounce(params => {setProposal(proposal => {
setProposal(proposal => {
let mutable = Object.assign({}, proposal);
for(let i = 0; i < mutable.scopes.length; i++) {
let scope = mutable.scopes[i]
for(let j = 0; j < scope.assemblies.length; j++) {
let assembly = scope.assemblies[j]
for(let k = 0; k < assembly.items.length; k++) {
let item = assembly.items[k]
if(item._id === id) {
console.log('1', item)
item = {
...item,
...params
}
console.log('2', item)
}
}
}
}
console.log('3', mutable)
return mutable
})
}, 350), [])
日志的输出如下所示:
1 { ...item data, taxable: false }
2 { ...item data, taxable: true }
3 { scopes: [{ assemblies: [{ items: [{ ...item data, taxable: false }] }] }] }
我设置了一个沙盒,您可以在其中查看行为 https://codesandbox.io/s/young-dew-w0ick?file=/src/App.js
另一件奇怪的事情是我在提案中有一个名为更改的对象。我为更改对象设置了一个原子并以类似的方式更新它,并且按预期工作。
扩展我们在评论中的小谈话:你必须克隆你想要变异的整个对象树,一路克隆每个级别。这在普通 javascript 中是相当乏味的,所以以牺牲一点性能为代价(这个例子正在沿途更新所有数组),这可以优化为更具可读性:
setProposal((proposal) => {
let mutable = proposal;
console.log("before", mutable);
mutable = {
...mutable,
scopes: mutable.scopes.map((scope) => ({
...scope,
assemblies: scope.assemblies.map((assembly) => ({
...assembly,
items: assembly.items.map((item) => {
if (item.id === id) {
return {
...item,
...params
};
} else {
return item;
}
})
}))
}))
};
console.log("after", mutable);
return mutable;
});