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. After using them for a while, the value became clear: custom hooks let you move repeated component logic into small functions.
After building several applications with hooks, I ended up with 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:
tsximport 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:
tsximport 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.