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.

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.