嗨,我正在尝试创建一个简单的多文件组件,但文件状态没有如预期的那样运行。
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
处理程序中使用它,那么有一些答案可以探索这些选项。