我正在尝试从放置请求中更新数组
const [descriptors, setDescriptors] = useState([]);
const handleDescriptorUpdate = (id, descriptorData) => {
services
.putDescriptor(id, descriptorData)
.then((response) => {
const descriptorIndex = _.findIndex(descriptors, (e) => e.id === id);
if (descriptorIndex !== -1) {
const tempDescriptors = [...descriptors];
tempDescriptors[descriptorIndex] = response.data;
setDescriptors(tempDescriptors);
}
})
.catch((error) => {
console.error(error);
});
};
当我一次仅执行1个请求时,这很好用,但是当我单击执行两次承诺的更新的按钮时,而不是展开数组并用新的值更新旧值,两者都在传播同一数组,导致在解决第二个承诺时,它使用从服务器 BUT 返回的新值(第二个值)更新状态,从而更改第一个值(被第一个承诺更改的对象)保留其原始值。
描述符最初由对象数组填充(来自get请求):
[
{
"id": 24,
"name": "Test 4.1",
"percentage": 0,
"towerId": "5cfc9200-c04a-11e9-89c0-2dd5d3707b1b"
},
{
"id": 23,
"name": "Test 3.1",
"percentage": 0,
"towerId": "5cfc9200-c04a-11e9-89c0-2dd5d3707b1b"
}
]
答案 0 :(得分:1)
即使React batches all setStates done during an event handler。
setDescriptors
在事件处理程序的范围之外 ,因为只有在解决诺言后才调用它。
因此,您需要使用state callback来正确管理描述符版本。
.then((response) => {
setDescriptors((descriptors) => ( // use state callback
descriptors.map((desc) =>
desc.id === id ? { ...desc, ...response.data } : desc
)
})
}
答案 1 :(得分:0)
我看到您让描述符作为状态而不是引用,正如我在上面的评论中所说,useState不会立即反映更改,因此请在内存中保留数组的一个引用,您可以使用钩子useRef来实现,请参见下一个示例:
const [descriptors, setDescriptors] = useState([]);
const descriptorsReference = useRef(null);
const handleDescriptorUpdate = (id, descriptorData) => {
services
.putDescriptor(id, descriptorData)
.then((response) => {
const descriptorIndex = _.findIndex(descriptors, (e) => e.id === id);
if (descriptorIndex !== -1) {
// Use descriptorsReference instead
const tempDescriptors = [...descriptorsReference.current];
tempDescriptors[descriptorIndex] = response.data;
// Next line is to update the descriptors into descriptors state, this phase doesn't happen immediately 'cause is asynchronous
setDescriptors(tempDescriptors);
// Next line is to update the descriptors in memory, this phase occurs immediately
descriptorsReference.current = tempDescriptors
}
})
.catch((error) => {
console.error(error);
});
};