skip to Main Content

I have a handler for a form submit that takes a user image, sends it to the back, does stuff on that image, and gives the modified image back (as a base64) to the front to be displayed.

Sending and receiving the image from the back works fine. But after receiving the image in the front API, I cannot give it to front Component, because the component handler is not waiting for the front API return.

Component that has the form and handler :

function Workshop() {

  // Used to store and update the front when data are modified
  const [imageUpload, setImageUpload] = useState(); 
  const [imageGenerated, setImageGenerated] = useState();

  // Handle the submit of the form
  const handleSubmit = event => {
    event.preventDefault();

    // Append the user image to the formData object
    setImageUpload(event.target.files[0]);
    const formData = new FormData();
    formData.append("file", imageUpload);

    // Calls the FrontEnd API with the image to be modified
    if(imageUpload) {
      const res = frontAPI.callGenerateImage(formData);
      console.log("back to front"); // ### THIS IS WHERE IT DOESNT WORK ###
      console.log(res); // ### THIS IS WHERE IT DOESNT WORK ###
      setImageGenerated(res); // ### THIS IS WHERE IT DOESNT WORK ###
    }
  };

  return (                                                                                                                                                                                                                                                                                                                                        
    <>
      <div className="workshop">
        <form method="post" onSubmit={handleSubmit} encType="multipart/form-data">
            <input type="file" name="imageUploader" onChange={handleImagePreview} />
            <img alt="preview image" src={imagePreview} />
            <button type="submit">Modify Image</button>
        </form>
        <img alt="generated image" src={"data:image/jpeg;base64," + imageGenerated} />
      </div>
    </>
  );
}

export default Workshop;

FrontEnd API with the fetch :

export function callGenerateImage(formData) {
  var  base64;
  fetch("/generator", {
    method: "POST",
    body: formData
  })
  .then(data => data.json())
  .then(res => {
    base64 = Buffer.from(res.data, "binary" ).toString("base64");
    console.log(base64); // THIS IS THE BASE64 STRING IN THE OUPUT BELOW
    return base64;
  })
};

Output :

enter image description here

So as you can see, I do receive the base64 stream of my modified image, but the line const res = fontAPI.callGenerateImage(formData); doesn’t wait for the actual return of the fetch and goes on with the console.log("back to front"); .

I tried to switch my API function to an async function and change

const res = frontAPI.callGenerateImage(formData);

to

const res = await frontAPI.callGenerateImage(formData);

But it doesn’t work because I’m not at top level, even if I remove the "if", as I am in a function of the component.

I’m fairly sure that the answer is pretty simple but I don’t see it.

Thanks a lot for your help !

EDIT : PROBLEM SOLVED, SEE MY ANSWER BELOW

2

Answers


  1. Chosen as BEST ANSWER

    I got it to work thanks to jbcortez89 and lo-fi wi-fi.

    I needed to fix 2 things in my code :

    A) Switching the handler to an async function, which I didn't even know was possible this way, which somehow allows me to use await even if I'm not at top level :

    const handleSubmit = async (event) => {
    event.preventDefault()
    if (imageUpload) {
        const formData = new FormData();
        formData.append("file", imageUpload);
    
        const res = await frontAPI.callGenerateImage(formData);
        setImageGenerated(res);
    }
    

    B) Fix my API fetch return value. I decided to switch to the new format which is much clearer than the nested then().

    export async function callGenerateImage(formData) {
      let myData = await fetch("/generator", {
        method: "POST",
        body: formData
      })
      
      let dataJSON = await myData.json();
      return Buffer.from(dataJSON.data, "binary" ).toString("base64"); 
    };
    

    thanks a lot guys for your help !


  2. Use async/await in your submit function and you’ll be able to get the result.

    const handleSubmit = async (event) => {
        event.preventDefault()
    
        const file = event.target.files[0];
    
        if (file) {
            const formData = new FormData();
            formData.append("file", file);
    
            const res = await frontAPI.callGenerateImage(formData);
            setImageGenerated(res);
        }
    }
    

    Also, you shouldn’t set state and then check the state value within the same function. When you run setImageUpload() and then check if (imageUpload), you’re not going to get the updated state until the next time you call the submit function. Instead, set it to a variable like I did.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search