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.