Use previous value through a React hook
React Hooks took me a little while to get used to after they were introduced in React v16.8.0. Once they clicked, the appeal was obvious: custom hooks let you move repeated component logic into small functions.
A few apps in, I had a small library of patterns I reuse often.
One of those patterns is reading the previous value of state or props. It only takes a few lines and uses useRef(). A ref can point at an HTML element, but it can also store any value you assign to it.
Combined with useEffect(), that gives us a small usePrevious() hook:
import React from 'react';
export default function usePrevious<T>(value: T): T {
// Create a reference to hold the previous version of the value,
// as it is basically a generic object whose `current` property can hold any value.
const ref = React.useRef<T>();
// Use the `useEffect` hook to run a callback...
React.useEffect(() => {
// ...to store the passed value on the ref's current property...
ref.current = value;
}, [value]); // ...whenever the value changes.
// And return the currently stored value,
// as this will run before the `useEffect` callback runs.
return ref.current;
}
What to do with this hook?
When you combine usePrevious() with state, you can run logic when a value differs from the previous render. I often use it to compare boolean values, like a loading state:
import React from 'react';
const Application = () => {
// Call some external API through a custom hook.
const { data, loading } = useAsyncApi()
// Pass its loading indicator to our created hook.
const wasLoading = usePrevious<boolean>(loading);
// Use the `useEffect` hook to run a callback...
React.useEffect(() => {
// ...to check if the API was loading but now it is completed...
if (!loading && wasLoading) {
// ...and run some arbitary code...
}
}, [loading, wasLoading]); // ...whenever one of these changes.
return (
<div>
{/* ... */}
</div>
);
}It is a small hook, but it is useful whenever the current render needs to know what changed since the previous one.