3

I have two components, one that uploads a file, and another that is a form that can be submitted. The uploader has a callback for when the upload is complete and the form has a callback for when the form is submitted. My goal is to make a request to the backend when the uploader is done uploading and the form has been submitted, without caring which happens first.

My current solution is something like this:

const [isFileUploaded, setFileUploaded] = useState(false);
const [isFormSubmitted, setFormSubmitted] = useState(false);

const handleUploadFinish = ( {signedBlobId} ) => {
    // update params to be sent to the backend with the signedBlobId

    setFileUploaded(true)

    if (isFormSubmitted) {
        // make the backend call
    }
}

const handleFormSubmitted = (values) => {
    // update params to be sent to the backend with the values

    setFormSubmitted(true)

    if (setFileUploaded) {
        // make the backend call
    }
}

However, I read in the React documentation on state that setting state is an asynchronous operation. This makes me worry that it's possible that if both callbacks happen to be called at nearly exactly the same time, it's possible that both isFileUploaded and isFormSubmitted will still be false when they are checked, preventing the backend call from happening.

Is this a valid concern? If so, what is a better way of handling this?

Rob
  • 14,746
  • 28
  • 47
  • 65
Blargel
  • 358
  • 2
  • 10
  • Is it required to have an upload before submitting the form? Is the upload and submit happening at the same time? – Chris Ngo Jul 27 '19 at 19:49
  • 1
    You already answered the question with exactly what I was looking for, but just to clarify, here's some more details on what I'm doing. The user is presented with both the uploader and a form at the same time. He can then start an upload and then fill out the form while the upload is finishing. When he submits the form, if the upload is still in progress, the form will hide itself and wait for the upload to finish before making the api call. If the upload is complete when the form is submitted, it will make the api call immediately. – Blargel Jul 27 '19 at 20:27
  • Awesome, sounds like my solution worked for you then :) – Chris Ngo Jul 27 '19 at 20:28

1 Answers1

1

Yes, with the way you have your logic constructed there will likely be race-conditions. You should want your code to have a more synchronous pattern. Fortunately, there is a way to resolve this by integrating the useEffect() hook. Essentially it will be triggered anytime a value you are subscribing to has changed.

In this case we want to verify that both isFileUploaded and isFormSubmitted are true, only then will we make the final backend API call.

Consider an example like this:

import React, { useState, useEffect } from "react"

const myComponent = () => {

    const [isFileUploaded, setFileUploaded] = useState(false);
    const [isFormSubmitted, setFormSubmitted] = useState(false);
    const [params, setParams] = useState({})

    const handleUploadFinish = ( {signedBlobId} ) => {
        // update params to be sent to the backend with the signedBlobId
        setFileUploaded(true)
    }

    const handleFormSubmitted = (values) => {
        // update params to be sent to the backend with the values
        setFormSubmitted(true)
    }

    useEffect(() => {
        if(isFormSubmitted && isFileUploded){
           ...make backend call with updated params
        }
    }, [isFormSubmitted, isFileUploaded])

   return(
      ....
   )
}
Chris Ngo
  • 15,460
  • 3
  • 23
  • 46