Home > Mobile >  How to get the result of a Promise in useEffect
How to get the result of a Promise in useEffect

Time:09-29

Having the following code snippet:

  useEffect(() => {
    if (uploadedFile) {
      const uploadedFileText = uploadedFile[0].text().then((a) => {
        return a;
      });

      const parsed = JSON.parse(uploadedFileText);
      setParsedFile(parsed);
    }
  }, [uploadedFile]);

The type of uploadedFile: FileList | File[], which is a file uploaded in a field. In my case it is a JSON file but for some other methods in the code it needs to be uploaded as binary file.

In this useEffect it should be parsed as JSON file.

The above code says that there is an error on JSON.parse(...):

Argument of type 'Promise' is not assignable to parameter of type 'string'.

It suggests as a quick fix to add await inside JSON.parse : const parsed = JSON.parse(await uploadedFileText);

But this for sure isn't working as useEffect isn't async and cannot add async to it.

How to fix this issue?

CodePudding user response:

useEffect callback cannot be async but you can add an async function in its body.

    useEffect(() => {
        async function parseFile() {
            if (uploadedFile) {
                const uploadedFileText = await uploadedFile[0].text().then((a) => {
                    return a;
                });

                const parsed = JSON.parse(uploadedFileText);
                setParsedFile(parsed);
            }
        }
        parseFile();
    }, [uploadedFile]);

CodePudding user response:

Slightly different answer from the others, because I don't know why you insist on returning the value of uploadedFile :

useEffect(() => {
   // note: your condition was also potentially wrong
   if (uploadedFile?.length) {
      uploadedFile[0].text().then(uploadedFileText => {
         const parsed = JSON.parse(uploadedFileText);
         setParsedFile(parsed);
      }).catch(err => {
         // TODO : proper error management, file could not be parsed
      });
   }
}, [uploadedFile]);

CodePudding user response:

Or you can doing in other way with creating seprate functions for logic only. You don't need to include all the code inside useEffect function.

       const parseFile = useCallback(async () => {
            const uploadedFileText = await uploadedFile[0].text().then((a) => {
                return a;
            });
            const parsed = JSON.parse(uploadedFileText);
            setParsedFile(parsed);
        }, []);

        useEffect(() => {
            if (uploadedFile) {
                parseFile();
            }
        }, [uploadedFile]);

CodePudding user response:

You can actually get around the useEffect Async/Await constrains by creating an inner function that is Async:

useEffect(() => {
  const uploadFile = async() => {  // <- Your new Async Function
    if (uploadedFile) {
      const uploadedFileText = await uploadedFile[0].text();

      const parsed = JSON.parse(uploadedFileText);
      setParsedFile(parsed);
    }
  }
  uploadFile();  // <- Then you just call it at the bottom of the useEffect
}, [uploadedFile]);
  • Related