0

I am developing an application in React. It has a simple search box, on submit , i am calling api1, which returns an array of data. For each of the item in the array, i need to call api2 - which should be async. Currently the code is something like this:

onSubmit() { 
    api1(textboxvalue).then(data => { 
        let currentComponent = this      
        if(data matches condition1) {
        currentComponent.state.arrayOfElements1.push(data);
        }               

        if(data matches condition2) {
        currentComponent.state.arrayOfElements2.push(data);
        }               

        const arrayOfElements1 = this.state.arrayOfElements1
        arrayOfElements1.map(function (element) {
        api2(element) -> set this.state.data1loaded

        })

        const arrayOfElements2 = this.state.arrayOfElements2
        arrayOfElements2.map(function (element) {
        api2(element) -> set this.state.data2loaded

    })

}

Requirement is check data1loaded and data2loaded states in render asynchronously. But with the above code, render is called only after promise of api1 completes

Any thoughts ?

2 Answers 2

1

@amirKovacevic is totally correct. You should NEVER mutate state directly: https://reactjs.org/docs/state-and-lifecycle.html#do-not-modify-state-directly

I don't perfectly understand your code, but I imagine you want to do something like this:

onSubmit() {
  api1(textboxvalue).then(data => {
    if(/* data matches condition1 */) {
      this.setState(prevState => ({
        arrayOfElements1: [...prevState.arrayOfElements1, data]
      }), () => {
        const requests1 = Promise.all(this.state.arrayOfElements1.map(function 
          (element) {
            return api2(element)
          })).then(data => this.setState({ data1loaded: true })) // I assume you want to have an indication loading was complete
      })
    }
  })
}

Notice the callback hell I climbed myself into because I didn't use async/await. Also notice I used setState callback: https://reactjs.org/docs/react-component.html#setstate

Setting the state is asynchronous, so you shouldn't use it directly after using setState, at least not if you want to have the new values.

Also, my example is only for the first array of elements.

Oh, and I'm new on SO, so sorry if anything is not up to usual SO comment standards. :)

Sign up to request clarification or add additional context in comments.

2 Comments

how about this ? var updatedArray = this.state.arrayOfElements1.push(data); currentComponent.setState({arrayOfElements1: updatedArray})
Try doing it in the console (or node REPL). push() method doesn't return a new array, but the LENGTH of the new array. let arr = [1, 2, 3]; const x = arr.push(4); console.log(x) // logs 4, same as arr.length would Besides, again, NEVER mutate state directly. It won't end well for you. If you insist on creating a new variable for clarity, you can do const updatedArray = this.state.arrayOfElements1, push new data to it and then set it to new state.
1

You're pushing the result to the state, instead of using setState method that would re-render component with the new state. This has nothing to do with the async nature of Promises, but rather the way React works (simplified: updating state and passing state and props to components which causes them to render).

I suggest brushing up on React basics before moving forward.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.