React Custom Hooks for prevProps & prevState
Tags: react, webdev
Published: 2020-06-19 18:09:33

For long, we we used to write code like this inside of our React components:

```js
componentDidUpdate(prevProps, prevState) {
  // did 'count' increase from being 0?
  if ( prevProps.count === 0 && this.props.count > 0 ) {
    // do something
  }
}
```

Sometimes, you may not just want to know if a piece of prop/state changed, but also what its previous value was. It was easier in the lifecycle-methods-universe, but not so straight forward with functional components.

Today I'm going to share a simple, callback-based custom hook that can serve as a replacement for the code above.

I call the hook `usePrevValues`, and its API looks like:

```js
const MyComponent = ({ count }) => {
  usePrevValues(
    {
      count,
    },
    prevValues => {
      if (prevValues.count === 0 && count > 0) {
        // do the same thing here
      }
    }
  );

  return (
    /* JSX stuff */
  );
};
```

As you can see, the first argument is a plain object, whose key-value pairs are all the values from props & state (and even values derived from those) for which you want to track the previous values. The second argument is a callback function, which receives an object of previous values as argument.

### Breakdown

This hook works because of the [`useRef`](https://reactjs.org/docs/hooks-reference.html#useref) hook.

From the docs:

> `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument (`initialValue`). The returned object will persist for the full lifetime of the component.


Combining this with the more popular `useEffect` hook solves our problem: After each render, just before the effect is run, save the values to a ref value. React API provides such a point in the render cycle, through the "cleanup" method returned from the `useEffect` callback. And then, invoke the callback from inside the effect, with the ref object as the argument.

The body of our custom hook is as follows:

{% gist https://gist.github.com/danedavid/65d0720a0141282e9f60c8e0fdb4f2ea file=usePrevValues.js %}


## Follow Up:

A keen eye would notice that, though we can compare previous & next values and exclusively run code, our callback function gets executed in every render. This is because, on using the `useEffect` hook, we missed out the dependency array to prevent it from running after all renders. So we'll add it:

{% gist https://gist.github.com/danedavid/5fcfe154bb5c267e32bd2df84bc3e93f file=usePrevValues.js %}

But is this going to solve our problem? **No.** Because, during each render, we're passing a new object literal as `value` and a new function reference as `callback`. Fortunately, React has solutions for both: `useMemo` and `useCallback`. Thus, to use the above hook without unnecessary invokations of the callback, we write it as follows:

{% gist https://gist.github.com/danedavid/5fcfe154bb5c267e32bd2df84bc3e93f file=usage.js %}

That's it! It's wonderful how, with React hooks, solutions form automagically by combining the basic hooks.

I hope the above write-up made sense, and was easy to grasp. If not, or if you liked this post & would like to let me know, drop a comment below!

----

Also you can find me on Twitter - [@this_dane](https://twitter.com/this_dane), or on Github - [danedavid](https://github.com/danedavid).
Stay safe!