What is the recommended way to update the files progress in React?

Hello, I am using Uppy in a react project to upload 5K+ images together, and the progress for each files should be updated in real time. when uploading large number of files the app crashes but when uploading 50 images everything works fine. if I stopped updating the state on each ‘upload-progress’ everything works fine even with the 5K images. So, I think that the ‘upload-progress’ function is updating the state so many times that causes the app to crash.

what do you recommend to update the progress in real-time ?

so I have something like this right now:

import { useState } from "react";
import Uppy from "@uppy/core";
import AwsS3 from "@uppy/aws-s3";

const MiddleSection = ({ setProgressFilePer }) => {
  const updateFileProgress = (fileId, progress) => {
    setProgressFilePer((prevFiles) => {
      // Find the index of the item you want to update
      const index = prevFiles.findIndex((el) => el?.fileId === fileId);

      // If the item exists, update it
      if (index !== -1) {
        return prevFiles.map((file, i) =>
          i === index ? { ...file, progress: progress } : file
        );
      }

      // If the item doesn't exist, add it
      return [...prevFiles, { fileId: fileId, progress: progress }];
    });
  };

  uppy.on("upload-progress", (file, progress) => {
    updateFileProgress(
      file?.id,
      Math.floor((progress?.bytesUploaded / progress?.bytesTotal) * 100)
    );
  });
};

const Progress = ({ progress }) => {
  <div className="barGreen" style={{ width: `${progress}%` }}></div>;
};

const LeftSection = ({ files, progressPerFile }) => {
  return (
    <>
      {files.map((el) => {
        const image = progressPerFile?.find((f) => el?.id === f.fileId);
        return (
          <div>
            <p>
              {el.name}
              <Progress counter={image?.progress} />
            </p>
          </div>
        );
      })}
    </>
  );
};

const App = () => {
  const [progressPerFile, setProgressPerFile] = useState([]);
  const [files, setFiles] = useState([]);

  const uppyInstance = (allowedFileTypes, id) => {
    return new Uppy({
      id: id,
      autoProceed: false,
      restrictions: {
        allowedFileTypes, // Set allowed file types
      },
    }).use(AwsS3, {
      companionUrl: "/api/upload-center/",
      limit: 5,
      getChunkSize: () => 30,
      shouldUseMultipart: (file) => file.size > 50 * 1024 * 1024,
      companionHeaders: {
        "access-token": api_token,
      },
    });
  };

  const [imagesUppy] = useState(() =>
    uppyInstance(["image/jpg", "image/jpeg"], "ImageSeriesDropzone")
  );

  return (
    <>
      <LeftSection files={files} progressPerFile={progressPerFile} />
      <MiddleSection
        uppy={imagesUppy}
        setProgressPerFile={setProgressPerFile}
      />
    </>
  );
};

Hi, if I understand correctly, you are making your own UI with Uppy and therefor want access to the file progress?

We had a hook useUppyState to access uppy’s state reactively but had to revert because it was a breaking change.

You can recreate the hook for now:

import { useSyncExternalStore, useMemo, useCallback } from 'react'

export default function useUppyState(uppy, selector) {
  const subscribe = useMemo(
    () => uppy.store.subscribe.bind(uppy.store),
    [uppy.store],
  )
  const getSnapshot = useCallback(
    () => selector(uppy.store.getState()),
    [uppy.store, selector],
  )

  return useSyncExternalStore(subscribe, getSnapshot)
}

And then use it like so:

const [uppy] = useState(() => createUppy()) // keep createUppy outside of the component.
const files = useUppyState(uppy, (state) => state.files)
const totalProgress = useUppyState(uppy, (state) => state.totalProgress)  

Then you have access to files reactively inside React.