How to get the PREVIOUS state in React?

I am a software developer proficient in web application development. I also like creating UI/UX designs for web and mobile applications. I write about software development tips, resources and guides to get started.
Let's start by asking ourselves why would we need the previous state? There might be some cases where you need to render a different view which also changes the current state based on the previous state.
Consider a simple example - you have an ON/OFF toggle button. Let's get a bit adventurous and not use a boolean state. Instead, we use the string representation ON or OFF. This example is only to simplify the process of how to get the previous state.
We start defining a simple component <Toggle /> which renders the button with the initial state as ON.
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
const Toggle = () => {
const [buttonState, setButtonState] = useState("ON");
const handleClick = () => {
// our toggle logic will go here
}
return (
<div>
<button onClick={handleClick}>{buttonState}</button>
</div>
)
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
Here comes the key part. To get the previous state, we use the useRef() hook in React.
What's the use of useRef() here?
useRef() is a really powerful hook in React which provides a ref which stores a value that is similar to a state. Refs can have other use cases as well. This is just one of them. The main difference being, React does not re-render the UI if the ref's value changes unlike when a state's value changes.
We use a custom usePrevious() hook that would give us the previous value. The ref contains a .current property that holds the value. We will look into how it works down below.
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
// hook that would return the ref to the previous value
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref;
}
const Toggle = () => {
// component logic..
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
Finally, adding our toggle logic inside the handleClick function. We'll also render the previous state on the UI to see it clearly.
import React, { useState, useRef, useEffect } from 'react';
import ReactDOM from 'react-dom';
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref;
}
const Toggle = () => {
const [buttonState, setButtonState] = useState("ON");
// getting the value of the previous state
const previousState = usePrevious(buttonState);
const handleClick = () => {
// toggling logic
if(previousState.current === "ON")
setButtonState("OFF");
else
setButtonState("ON");
}
return (
<div>
<button onClick={handleClick}>{buttonState}</button>
<!-- we also render the previous state to see what changes happen -->
<p>Previous State: {previousState.current}</p>
</div>
)
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
How does this work?
During the first render when the usePrevious() custom hook is called, the useEffect does not run the () => ref.current = value until the first render finishes. So the hook returns undefined as the ref's value initially. Only during the next re-render, theuseEffect runs with the value that was passed to it in the previous re-render(i.e. "ON" from the first render) which enables it to store the previous value.
So this is what happens rendering in order,
- state = "ON", ref = undefined
- state = "OFF", ref = "ON" (value of ref comes from the previous render)
- state = "ON", ref = "OFF" and so on..
Hope you understood how you can use refs to get the previous state value. Share your comments and feedback down below! ๐
Ciao! ๐




