Halvor William Sanden

componentDidUpdate(): No prevState without prevProps

Before React Hooks, I used the React lifecycle method componentDidUpdate(). A common way to use it is/was to fetch data based on changes made by the user. Let’s say, selecting a date. If the user selects the same date as the current date, it’s nice to not go fetch the same data again. Avoiding blinking interfaces and unnecessary network requests. In order to do that, we compare the current date to the new selected date. This means we need to pass the current date, known as prevState, into the function.

The mistake
#

I knew it took three arguments, prevProps, prevState and snapshot. But I just needed prevState, and wrote:

componentDidUpdate(prevState) { 
  if (this.state.value !== prevState.value) { 
    // network request 
  }
}

And I ended up with network requests in an endless loop (always keep an eye on the console, unless you like angry servers). The request would repeat as long as this.state.value was not equal to prevState.value – which were never going to be equal because I wasn't really passing prevState, I was passing prevProps.

The fix
#

Turns out the names don't matter. In componentDidUpdate(prevProps, prevState, snapshot) you just need to have the arguments in their designated positions:

componentDidUpdate(prevProps, prevState, snapshot) {
 if (this.state.value !== prevState.value) {
   // network request
  }
}

And it worked. The lifecycle method runs after a date selector has changed its value. The method takes the changed value, this.state.value, and checks it against the previous value, prevState.value, finds them different and performs the network request. Then, it runs the comparison again, this time the two values will be equal and the method stops. If you don't need snapshot, it can be left out. If you only need prevProps, you can skip the other two. And you can name them whatever you want.

In the final code, I kept the names but added a low dash to prevProps as it is not in use.

componentDidUpdate(_prevProps, prevState) {
  if (this.state.value !== prevState.value) {
    // network request
  }
}

// Alternatively
componentDidUpdate = (_prevProps, prevState) => {
  if (this.state.value !== prevState.value) {
    // network request
  }
}

Thanks to Ashley_wnj for making and fixing the same mistake.