0

I have the following method in React and would like to complete the first two methods that uploads the images to cloudinary and sets the URL to the state as coded first before executing the API call addStudent since the update state values needs to be passed on.

Code below and intended order in comments. Currently if i look at Network in developer tools, it executes in correct order but last API call addStudent doesnt seem to wait until the setState's are executed in previous methods as it is crashing with base64 data.

How can I modify the below code to achieve the required order?

addStudent= e => {
  this.setState({step:0})  //renders a loading screen

  const files1 = Array.from(this.state.profilePic)
  const formData1 = new FormData()
  files1.forEach((file, i) => {
    formData1.append(i, file)}) 

  const files2 = Array.of(this.state.passportPhoto)
  const formData2 = new FormData()
  files2.forEach((file, i) => {
    formData2.append(i, file)})


//uploads profilePic to cloudinary and sets state to URL returned by the api call --> order 1
    fetch(`http://localhost:3030/image-upload`, {method: 'POST',body: formData1})
      .then(res => res.json())
      .then(images1 => {this.setState({profilePic: images1[0].url})})


//upload passportPic to cloudinary and sets state to URL returned by the api call --> order 2
      .then(fetch(`http://localhost:3030/imageUploadPassport`, {method: 'POST',body: formData2})
      .then(res => res.json())
      .then(images2 => {this.setState({passportPhoto: images2[0].url})})

//uses data in state objects above to enter data to SQL database  --> order 3
      .then(fetch(`http://localhost:3030/addStudent?profPicURL=${this.state.profilePic}&passportURL=${this.state.passportPhoto}`)
      .catch(err=>console.error(err))
      .then(this.setState({step:2008}))))   //displays a success screen

  }

Dworo
  • 153
  • 1
  • 4
  • 15
  • for async-await. you should create async function for each call, and only calls the second execution after the first one – Ray Jan 17 '20 at 07:20
  • 1
    @[dworo](https://stackoverflow.com/users/11846826/dworo): try to call **setState** once in the last **then**. **setState is asynchrounous, you may also try to use a **clallback** function that sets your **props**. – Meziane Jan 17 '20 at 07:30
  • 1
    Your code *already* executes in sequence. `then` waits for the previous call to finish before calling the next one. You should probably be asking why `setState` doesn't update the UI immediatelly. – Panagiotis Kanavos Jan 17 '20 at 09:55
  • Does this answer your question? [Does React keep the order for state updates?](https://stackoverflow.com/questions/48563650/does-react-keep-the-order-for-state-updates) – Panagiotis Kanavos Jan 17 '20 at 09:58
  • From the duplicate question `no matter how many setState() calls in how many components you do inside a React event handler, they will produce only a single re-render at the end of the event.` – Panagiotis Kanavos Jan 17 '20 at 09:58
  • @panagiotis I believe thats what i should be asking. All the other state variables that were updated in other methods prior to the application calling this last API call isnt reflected in the call either. Whats the fix for this? – Dworo Jan 18 '20 at 05:46

2 Answers2

0

addStudent= async e => {
  this.setState({step:0})  //renders a loading screen

  const files1 = Array.from(this.state.profilePic)
  const formData1 = new FormData()
  files1.forEach((file, i) => {
    formData1.append(i, file)}) 

  const files2 = Array.of(this.state.passportPhoto)
  const formData2 = new FormData()
  files2.forEach((file, i) => {
    formData2.append(i, file)})

  const data1 = await fetch('http://localhost:3030/image-upload', {method: 'POST',body: formData1});
  const image1 = await data1.json();
  
  const data2 = await fetch('http://localhost:3030/imageUploadPassport', {method: 'POST',body: formData2});
  const image2 = await data2.json();
  
  
  const data3 = await fetch(`http://localhost:3030/addStudent?profPicURL=${image1[0].url}&passportURL=${image2[0].url}`);
  
  this.setState({step:2008});

  }
Osman Safak
  • 255
  • 1
  • 5
  • The original code is already executing in sequence. The OP's actual question is why the intermediate `setState` calls don't seem to execute in sequence too – Panagiotis Kanavos Jan 17 '20 at 09:56
0

Use Javascript Promises to wait for asynchronous functions.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Partha Roy
  • 1,575
  • 15
  • 16