0

I have a react component, say, MyComponent with two props text and num which may change independently. Consider the following code:

componentDidUpdate(prevProps) {
  if (this.props.text !== prevProps.text || this.props.num !== prevProps.num) {
      this.getDataAPICall(this.props.text, this.props.num);
  }
}

// Incoming data is dependent on both text and num
getDataAPICall(text, num) {
  fetch(SOMEURL+'/text/num').then(d => d.json())
     .then(data => {
       setState({ renderdata: data });
  })

}

If only one of the props is changed, there is no problem. But, when props change such that, say, text changes from "a" to "b" and num changes from 1 to 2, I realized that componentDidUpdate is called two times with text and num values: text: "b", num: 1 and text: "b", num: 2.

Since num may or may not change (I can not know for sure), I have to call getDataAPICall with text: "b" and num: 1 as well. This causes two API calls (where the first one fetching the wrong data). Furthermore, depending on the completion time of the calls, the final state of the component may end up having the wrong data.

My question is: Is this the default behavior of componentDidUpdate or am I making a mistake in the parent component? If this is the default behavior, how can I avoid the first API call with the partially updated props?

Note: These two props are actually props of the parent component as well, which comes from redux store through mapStateToProps.

Thanks

Sinan
  • 1
  • 1
  • I think you are making a mistake somewhere. If you see componentDidUpdate called multiple times with different properties changed, means that those properties are _not_ changed at the same time, but after multiple render of parent component. – keul Feb 17 '21 at 16:47
  • @keul Thank you. If that's the case, I will look into it further. – Sinan Feb 17 '21 at 16:59
  • @OmerSinanSarac What is passing in those props and how are they changed? Making async requests and setting them on resolve may get some [unexpected results](https://stackoverflow.com/a/62751846/1641941). Make sure you only set state when it's the last prop change. – HMR Feb 17 '21 at 17:19

2 Answers2

0

From my understanding of your problem, you are using componentDidUpdate correctly. It wouldn't matter also where you would place the API call (parent component or child), since you are having a race by design (if text or num change, you have to call the API).

One possible way to resolve this is to use AbortControllers (https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort) to cancel the first request and reissue it after the second prop changes. This is a bit tricky since you will have to have a third state for the first on going request.

I hope this helps a bit

0

I forgot to write an answer after I solved the issue. This is a late answer but perhaps it will help someone in a similar situation.

The reason for multiple componentDidUpdate calls was the separate dispatches of the 'text' and 'num' props. Each dispatch to Redux store causes a component update for each prop connected to the component. In my case, it was possible to check both values and update them in Redux store within the same dispatch if any of them changed, which solved the problem. But if this is not possible, what Denis Sicun suggested in this answer seems to be the best way to go.

Thanks everybody for helping me solve the issue.

Sinan
  • 1
  • 1