为什么在记录时会更新react state(useState)而不更新



嗨,我正在尝试创建一个简单的多文件组件,但文件状态没有如预期的那样运行。

FileUpload组件工作正常,当用户选择一个文件并开始上传时,会调用onStart道具方法。然后,当它成功完成时,就会调用"onFinish"道具方法。这段代码似乎可以在onfinish方法中整合对象。它在被CCD_ 3修改之前对对象的旧值进行控制。我希望控制台中的文件对象值包括缓冲区键,因为它是在调用onStart方法时添加的,但它不在那里。

示例初始状态文件应为[]。当调用使用效果时,状态文件应更新为[{_id:"example_unique_id"}],然后将出现一个上传按钮。当用户选择一个文件,onStart修改对象,状态应更新为[{_id:"example_unique_id", buffer:{}],最后当它完成时,files应为[{_id:"example_unique_id", buffer:{}],但此处返回[{_id:"example_unique_id"}]

我会错过什么?

此外,我安装了React Dev工具,似乎状态在开发工具中更新得很好。

import React, { useState } from 'react'
import { useEffect } from 'react';
import unique_id from 'uniqid'
import FileUpload from "./../../components/FileUpload";
const InlineFileUpload = ({ onFilesChange }) => {
const [files, setFiles] = useState([]);
function onFinish(file, id) {
const old_object = files.filter((file) => file._id == id)[0];
console.log("old object on after upload", old_object);
}
const addFile = (file, id) => {
const old_object = files.filter((file) => file._id == id)[0];
const index = files.indexOf(old_object);
const new_files = [...files];
new_files.splice(index, 1, { ...old_object, buffer: file });
setFiles(new_files);
};
useEffect(() => {
const new_attachments = files.filter(({ buffer }) => buffer == undefined);
if (new_attachments.length == 0) {
setFiles([...files, { _id: unique_id() }]);
}
const links = files.filter((file) => file.file !== undefined);
if (links.length !== 0) {
onFilesChange(links);
}
}, [files]);
return (
<>
{files.map((file) => {
const { _id } = file;
return ( <FileUpload
key={_id}
id={_id}
onStart={(e) => addFile(e, _id)}
onFinish={(e) => onFinish(e, _id)}
/>
);
})}
</>
);
};
export default InlineFileUpload

我认为问题是由您的this代码没有更新状态引起的:

const addFile = (file, id) => {
const old_object = files.filter((file) => file._id == id)[0];
const index = files.indexOf(old_object);
const new_files = [...files];
new_files.splice(index, 1, { ...old_object, buffer: file });
setFiles(new_files);
}

files看起来像一个对象数组。Spread运算符不会对此数组进行深度复制。互联网上有很多例子,这里有一个。

let newArr = [{a : 1, b : 2},
{x : 1, y : 2},
{p: 1, q: 2}];
let arr = [...newArr];
arr[0]['a'] = 22;
console.log(arr);
console.log(newArr);

因此,您的new_files是同一个数组。Splice必须进行一些修改,但这些修改已经到位。因此,当您执行setFiles(new_files);时,您基本上设置了与newState相同的对象引用。React不会检测到更改,也不会更新任何内容。

您可以选择为特定代码实现深度复制方法或使用lodash-cloneDeep。看看您的代码,这可能对您有用:const new_files = JSON.parse(JSON.stringify(files))。它有点慢,并且您可能会失去具有值(如函数或符号(的属性。读取

获取旧日志的原因是因为闭包。

当您在addFiles函数中执行setFiles(new_files)时。React异步更新状态,但新状态在下次渲染时可用。

将被调用的onFinish函数仍然来自第一个渲染,引用该渲染的files。新渲染具有对更新文件的引用,因此下次再次登录时,将获得正确的值。

如果只是关于日志记录,请将其封装在useEffect挂钩中,

useEffect(() => {
console.log(files)
}, [files);

如果是在onFinish处理程序中使用它,那么有一些答案可以探索这些选项。

最新更新