How to get previous props/state with React Hooks
Tags: react, javascript
Published: 2020-01-08 14:37:04

---
title: How to get previous props/state with React Hooks
published: true
date: 2020-01-01 14:00:52 UTC
tags: react, javascript
canonical_url: https://blog.logrocket.com/how-to-get-previous-props-state-with-react-hooks/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/rf6x9b8pmhyjrnwyf1ne.png
---
**Written by [Ohans Emmanuel](https://blog.logrocket.com/author/ohansemmanuel/)**✏️

Accessing the previous props or state from within a functional component is one of those deceptively simple problems you’ll likely face as you work with React Hooks.

![React](https://blog.logrocket.com/wp-content/uploads/2019/12/react-previous-nocdn.png)

There’s currently no React Hook that does this out of the box, but you can manually retrieve either the previous state or props from within a functional component by leveraging the `useRef` hook.

How?

The solution [is discussed](https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state) in the official React documentation, and if you look in there you’ll find the following example, where `Counter` represents a simple counter component:

```jsx
function Counter() {
  const [count, setCount] = useState(0);

  const prevCountRef = useRef();
  useEffect(() => {
    prevCountRef.current = count;
  });
  const prevCount = prevCountRef.current;

  return <h1>Now: {count}, before: {prevCount}</h1>;
}
```

If you’re looking for an even quicker solution, you may abstract this functionality Into the custom Hook below:

```jsx
function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}
```

And use it within your application as follows:

```jsx
function Counter() {
  const [count, setCount] = useState(0);
  // 👇 look here
  const prevCount = usePrevious(count)

  return <h1> Now: {count}, before: {prevCount} </h1>;
}
```

Pretty simple, huh?

However, can you really explain how the `usePrevious` hook works?

I’ve shown how the problem is solved – a problem well-documented in the official docs. But the goal of this article isn’t to restate what’s been written in the official doc.

In the following section, I’ll explain in clear terms what’s happening within the custom Hook, and how the previous value is retained.

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

### useRef: The unsung Hooks hero

I work with Hooks everyday, both for personal projects and professional workplace projects.

In my experience, I’ve found that very few people really understand and take advantage of the `useRef` hook.

Apart from being great at handling DOM refs, the `useRef` hook is a perfect substitute for implementing instance-like variables within functional components.

Consider the following example with class components:

```jsx
// class component 
class Count extends Component {
  
   constructor() {
     this.specialVariable = "SPECIAL_VARIABLE"
   }
  
  render() {
    return null
  }
}
```

Every instantiated copy of the `Count` class will have its own `specialVariable` instance variable.

The `useRef` Hook can simulate this behavior, with an even more interesting feature.

```jsx
// functional component 

function Count() {
  const specialVariable = useRef("SPECIAL_VARAIBLE");
  return null
}
```

What’s interesting about the `useRef` hook is that it takes in an initial value to be stored — i.e: `useRef("INITIAL_VALUE")` — and it returns an object with a current property `{current: "INITIAL_VALUE"}`.

Whatever value was initially passed into the `useRef` Hook is saved to the `current` property of the `ref` object.

```jsx
function Count() {
  const specialVariable = useRef("SPECIAL_VARAIBLE");
  // specialVariable resolves to {current: "SPECIAL_VARIABLE"}

  return null
}
```

Unlike a ‘normal’ variable, the `specialVariable` ref object is not recomputed when the `Count` component is re-rendered. With the `useRef` Hook, the value saved in the `ref` object is kept the same across re-renders.

The value is not recomputed, nor is it lost. It remains the same.

Having said that, it’s worth mentioning that the only way to update the `ref` object is to directly set the value of the current property; e.g. `specialVariable.current = "NEW_SPECIAL_VARIABLE`.

Why is this explanation important?

Well, to understand what’s going on, let’s walk through the execution of the aforementioned solution to retrieving previous props/state step by step.

```jsx
// custom hook for getting previous value 
function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

// the App where the hook is used 
function Counter() {
  const [count, setCount] = useState(0);
  // 👇 look here
  const prevCount = usePrevious(count)

  return <h1>Now: {count}, before: {prevCount}</h1>;
}

// How the App is rendered 
<Counter />
```

Now, as soon as the rendering process for the `Counter` app begins, what happens?

(1) The `useState` hook is invoked and the variables `count` and `setCount` set. Note that `count` is now `0`.

![Function counter](https://blog.logrocket.com/wp-content/uploads/2019/12/function-counter-nocdn.png)

After this, the next line is executed.

(2) the `usePrevious` Hook is invoked with the current value of the count state variable, `0`.

![const prevCount](https://blog.logrocket.com/wp-content/uploads/2019/12/const-prevCount-screenshot-nocdn.png)

Upon invoking the usePrevious Hook, the following happens:

(3) A new `ref` object is created.

![Use ref](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2019/12/const-ref-useref.png?resize=730%2C411&ssl=1)

This ref object is initialized without an initial value, so the object returned is this: `{current: undefined}`

This next step is where most people slip up.

(4) The `useEffect` call is NOT invoked. Instead, the return value of the custom Hook is invoked.

![return ref.current;](https://blog.logrocket.com/wp-content/uploads/2019/12/return-ref-current-nocdn.png)

`ref.current` is returned, which in this case is `undefined`.

Why this behavior? i.e skipping the `useEffect` call?

Well, the `useEffect` hook is only invoked after the component from which it is called has been rendered (i.e, the return value of the component must be executed first.

So, what happens next?

(4) The execution within the component is resumed. This time, the `prevCount` variable holds the value `undefined`.

![prevCount](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/12/prevCount.png?resize=730%2C410&ssl=1)

(5) Next, the return value of the component is evaluated:

![now count](https://blog.logrocket.com/wp-content/uploads/2019/12/Now-count-before-prevCount-nocdn.png)

This returns the following to the screen: `<h1>Now: {count}, before: {prevCount}</h1>`, where count and `prevCount` are `0` and `undefined`.

(6) The `useEffect` call within the `usePrevious` hook is now invoked asynchronously in order to avoid blocking the browser from painting the DOM changes. `useEffect` is invoked after the render of the functional component.

![useEffect](https://blog.logrocket.com/wp-content/uploads/2019/12/seven-nocdn.png)

Here’s what we have within the effect function:

```jsx
useEffect(() => {
    ref.current = value;
});
```

The line within the `useEffect` function updates the current property of the `ref` object to value. What’s the value now?

`value` represents what the custom Hook was initially called with.

In this case, the value is `0`. In this current flow, remember `usePrevious` has only been called once with the initial value of `0`.

![eight](https://blog.logrocket.com/wp-content/uploads/2019/12/eight-value-nocdn.png)

Now, the ref holds the value `0`.

What happens when the count state variable within the app is updated from 0 to 1 (or a new count)?

The same flow is re-triggered.

The `usePrevious` Hook is invoked with the new state value `1`. Then, the return statement is evaluated (return `ref.current`), which would be 0 — not 1 since the ref object isn’t updated yet.

`ref.current` here is the previous value stored before the `useEffect` was triggered, or `0`.  
The `return` statement of the component is equally evaluated with the previous value successfully returned.

Only after the render is the `useEffect` call within the `usePrevious` Hook updated with the new value, `1`.

This cycle continues – and in this way, you’ll always get the previous value passed into the custom Hook, `usePrevious`.

### Why this Works

To appreciate why this works this way, you must remember the following:

1. The `ref` object will always return the same value held in `ref.current`, except when explicitly updated.
2. `useEffect` is only called after the component is rendered with the previous value. Only after the render is done is the ref object updated within `useEffect`.

By taking advantage of these two facts, you can easily replicate this functionality on your own.

### Conclusion

The fact that the `ref` object returned from invoking `useRef` remains the same across re-renders of a functional component is a powerful feature to embrace. It does this without you having to pass in any array dependency like in `useMemo` or `useCallback`.

Combine the ability to use `useRef` as an instance variable with the fact that the `useEffect` Hook is always triggered after the return statement of the parent component is evaluated, and you have an invaluable weapon at your fingertips.

You can find even more use cases for these and gain a deeper understanding of how this works to truly master Hooks.

Would you like to learn advanced React patterns using Hooks with me? Then join my soon-to-be released [Udemy](https://docs.google.com/forms/d/e/1FAIpQLSdAQmtQWqzsrWW7GDrlSPRTReE3yL9cdcP8NIE3nzbXldhtDQ/viewform).

You’ll be first to know when I [launch the course](https://forms.gle/VjnDckzs7JFFCGQq8).

* * *
## Full visibility into production React apps 

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, [try LogRocket.](https://www2.logrocket.com/react-performance-monitoring)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/r8kriwk3r8yqi48gy1z4.png)

[LogRocket](https://www2.logrocket.com/react-performance-monitoring) is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — [start monitoring for free.](https://www2.logrocket.com/react-performance-monitoring)
* * *

The post [How to get previous props/state with React Hooks](https://blog.logrocket.com/how-to-get-previous-props-state-with-react-hooks/) appeared first on [LogRocket Blog](https://blog.logrocket.com).