Implement and understand usePrevious hook
How come useRef in React can be used to keep track of the previous value?

Just a guy who loves to write code and watch anime.
Introduction
You've probably seen the pattern where useRef is used to keep track of the previous value of a state. But how does it always stay one time behind the useState?
That's what we'll dive into today!
usePrevious hook
import { useRef, useEffect } from "react";
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
We have a custom hook called usePrevious that takes a value and returns the previous value. Let's break it down:
We import
useRefanduseEffectfrom React.We define a function called
usePreviousthat takes avalueas an argument.We create a
refusinguseRef().We set the
ref.currentto thevalueinside theuseEffecthook.We return
ref.current.
So, how come ref.current always stays one time behind the useState?
To understand this, we have to understand how useRef and useState work.
useRef
useRef returns a mutable object whose .current property is initialized to the passed argument (initial value). Mutating the .current property doesn't trigger a re-render. This is important to understand because it allows us to store mutable values that persist across renders.
useState
useState returns an array with two values: the current state and a function to update the state. When you call the update function, React schedules a re-render with the new state.
Why useRef stays one time behind useState
During the very first render of the component, useEffect hasn't had a chance to run yet. React's effect hooks run after the render phase. This is intentional so that they don't block the rendering process. This also applies to every re-render.
Now that we understand the different pieces, let's go over the flow:
During the initial render, the
useRefhook is initialized with the providedinitialValue, settingref.currentto that value.After the component renders and commits to the DOM, the
useEffectruns and updatesref.currentwith thenewValue. Remember, this happens after the render phase. "Commit" means that React has applied the changes to the DOM.However, this update to
ref.currentdoes not trigger a re-render of the component.On the next render cycle (e.g. when state/props change), the
useRefhook returns the same ref object it created during the initial render.This means that
ref.currentstill holds thenewValuefrom the previous render, not the current value.During that next render,
ref.currentwill hold thenewValuethat was assigned in the previous render'suseEffect.- This is the key point to understand. The
useEffecthook updates theref.currentvalue, but that update doesn't trigger a re-render. That's why it doesn't update the UI that holds the ref value.
- This is the key point to understand. The
Conclusion
Understanding how the usePrevious hook works requires understanding useRef, useState, useEffect and the order in which they run. By understanding these concepts, you can build more complex hooks and components that leverage the power of React's hooks system.






