Perfect previous value hook in React
TLDR; Here is the code
export const usePrevRef = <T>(value: T) => {
const currentRef = useRef<T>()
const prevRef = useRef<T>()
prevRef.current = currentRef.current
currentRef.current = value
return prevRef
}
Why do we need two refs to accomplish such a look-simple task?
Longer story
Imagine that there are 3 phases in a useEffect
hook.
- Render phase: in the render function, outside the
useEffect
body - Effect phase: in the
useEffect
body, outside the disposal function - Disposal phase: in the disposal function
In the caller hook, to have the ref returned from usePrevRef
reflected the correct value in all these 3 phases, the update must happen before the caller's render(⑥). This means the best place to update the ref's value is ⑤.
From currentRef
's point of view, in the above code, currentRef.current
holds the value in the previous render, waits until the next render, and passes its value to prevRef
.
Note that in ⑧, the ref does not refer to the correct value.