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?
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(
....
)
}