首页 > 解决方案 > 异步函数应仅更新一项时覆盖数组状态

问题描述

我有一个文件上传组件。行为很简单:我向每个文件的后端发送一个上传请求,随着上传进度的增加,我有一个应该随之增加的栏。

我有一个包含每个选定文件及其各自进度的状态,例如:

interface IFiles {
    file: File;
    currentProgress: number;
}
const [selectedFiles, setSelectedFiles] = useState<IFiles[]>([]);

并且当用户点击上传按钮时,该函数将被触发并调用uploadFile我数组状态下的每个文件。

const sendFilesHandler = async () => {
        selectedFiles.map(async (file) => {
                const fileType = file.file.type.split('/')[0];
                const formData = new FormData();
                formData.append(fileType, file.file);
                formData.append('filename', file.file.name);
                await uploadFile(formData, updateFileUploadProgress);
        });
    };

这是uploadFile函数的样子。

const uploadFile = async (body: FormData, setPercentage: (filename: string, progress: number) => void) => {
    try {
        const options = {
            onUploadProgress: (progressEvent: ProgressEvent) => {
                const { loaded, total } = progressEvent;
                const percent = Math.floor((loaded * 100) / total);
                const fileName = body.get('filename')!.toString();

                if (percent <= 100) {
                    setPercentage(fileName, percent)
                }
            }
        };

        await axios.post(
            "https://nestjs-upload.herokuapp.com/",
            body,
            options
        );

    } catch (error) {
        console.log(error);
    }
};

如您所见,当 uploadProgress 被触发时,它应该通知调用 setPercentage 函数,即:

const updateFileUploadProgress = (fileName: string, progress: number) => {
        console.log('Entrada', selectedFiles);
        const currentObjectIndex = selectedFiles.findIndex((x) => fileName === x.file.name);
        const newState = [...selectedFiles];
        newState[currentObjectIndex] = {
            ...newState[currentObjectIndex],
            currentProgress: progress,
        };
        setSelectedFiles(newState);
        console.log('Saída', newState);
    };

这个函数应该只更新我的状态数组中文件名匹配的对象。然而,它压倒了整个事情。行为如下:

在此处输入图像描述

因此,只要我更新同一个对象,似乎一切都很好。onUploadProgress但是在被触发到另一个对象的那一刻,selectedFiles状态又变成了它的初始状态。为了使这项工作正常工作,我缺少什么?

标签: javascriptreactjstypescriptnext.js

解决方案


不确定这种行为背后的确切原因是什么,但在花了 3 个小时之后,我想出了以下出人意料的简单解决方案。

const updateFileUploadProgress = (fileName: string, progress: number) => {
  setSelectedFiles(prevState => {

    const currentObjectIndex = prevState.findIndex((x) => fileName === x.file.name);
    const newState = [...prevState];

    newState[currentObjectIndex] = {
      ...newState[currentObjectIndex],
      currentProgress: progress,
    };

  return newState;
  })
};

我能够在本地模仿您的问题,并用上述方法解决了它。我认为这是因为该函数(出于某种原因)即使在重新渲染之后仍然引用了初始状态。


推荐阅读