1

I have a hook component that allows a user to upload a set of images. I want to set it up in such a way that when the component is un mounted that all the files are uploaded to my backend.

currently using useEffect with a return of a function as the componentWillUnmount substitute, however when the function is called the state that it requires (the set of files uploaded) is empty i.e. empty list. Is there a way to fix this or a better way to do it? I suspect its because the useState for the stagedUploadedImages is set to an empty list. Its not an option to lift the state out of this component.

  const [stagedUploadedImages, setStagedUploadedImages] = useState([]);

  const uploadStagedFiles = () => { 
// when this is reached by the useEffect method `stagedUPloadedImages` is empty list
    stagedUploadedImages.forEach((file) => {
      const formData = new FormData();
      formData.append("files", file);

      api.uploads.uploadWithNoAssociation(formData).then((response) => {
        console.log("ImageGallery: response: ", response);
      });
    });
  };


  useEffect(() => {
    return () => {
      uploadStagedFiles();
    };
  }, []);

  const handleUpload = (files) => {
      setStagedUploadedImages([...files]);
  };

SwimMaster
  • 351
  • 3
  • 17
  • Where are you calling `setStagedUploadedImages()`? – BenM Mar 04 '21 at 20:41
  • I call it in the add images logic – SwimMaster Mar 04 '21 at 20:42
  • You should use [`useCallback()`](https://dmitripavlutin.com/dont-overuse-react-usecallback/). – BenM Mar 04 '21 at 20:43
  • @BenM the button that "submits" the form is not in this component, it is in the parent. And I can not make special code in the parent just for this component. – SwimMaster Mar 04 '21 at 20:47
  • @BenM if I wrap `uploadStagedFiles` in `useCallback` it still fails. – SwimMaster Mar 04 '21 at 20:50
  • Could you share the code where setStagedUploadedImages() is called in this component? – Alex Coleman Mar 04 '21 at 20:51
  • @AlexColeman see the bottom of the question – SwimMaster Mar 04 '21 at 20:55
  • 1
    I believe this answers your question: https://stackoverflow.com/questions/61956823/why-cant-useeffect-access-my-state-variable-in-a-return-statement – Szabó Sebestyén Mar 04 '21 at 21:01
  • @SzabóSebestyén It worked if they upload all their files at the same time and therefore only cause the component to rerender once however if they upload the files separately, then it will cause the uploadStagedFiles to fire the second time thereby uploading the first set of files. Which is not what I want. – SwimMaster Mar 04 '21 at 21:05
  • @SwimMaster Have you tried the createRef solution in the example? Adding to the dependency list is an obvious no go in your case. – Szabó Sebestyén Mar 04 '21 at 21:10
  • @SzabóSebestyén I made the value a ref and it was still an empty list in stagedUploadedImages – SwimMaster Mar 04 '21 at 21:18

1 Answers1

2

Explanation: https://www.timveletta.com/blog/2020-07-14-accessing-react-state-in-your-component-cleanup-with-hooks/

const [stagedUploadedImages, setStagedUploadedImages] = useState([]);

const valueRef = useRef();

const uploadStagedFiles = () => { 
  valueRef.current.forEach((file) => {
    const formData = new FormData();
    formData.append("files", file);

    api.uploads.uploadWithNoAssociation(formData).then((response) => {
      console.log("ImageGallery: response: ", response);
    });
  });
};

useEffect(() => {
  valueRef.current = stagedUploadedImages;
}, [stagedUploadedImages]);

useEffect(() => {
  return () => {
    uploadStagedFiles();
  };
}, []);

Additional info: https://dmitripavlutin.com/react-hooks-stale-closures/