Recently, I was creating a react component and I wanted to remember the previous value of one of the props. I did a google search and found several different articles[1][2][3], all trying to convince me that the following code would serve my needs. This snippet is from react's documentation:
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
The idea with this pattern is that the useEffect
hook will fire its effect whenever the value
variable changes. Since the effect fires after the function returns, the hook will return whatever value
was the last time the hook was called not the previous value
.
This means that in my component, instead of getting the previous value of a prop, I get the value of the prop on the previous render. Consider the following component.
function Counter(props) {
const { style } = props;
const [count, setCount] = useState(0);
const prevCount = usePrevious(count);
return (
<h1 style={style}>
Now: {count}, before: {prevCount}
</h1>
);
}
If the style
prop changes, it will cause an update to the component, and prevCount
will suddenly display the same value as the current count. According to the react docs team this is intended behaviour. However if you are like me, consider using the following code instead:
function usePrevious(value, initial?) {
const targetRef = useRef(value);
const previousRef = useRef(initial);
if (targetRef.current !== value) {
// The value changed.
previousRef.current = targetRef.current;
targetRef.current = value;
}
return previousRef.current;
}
or with a singe ref
function usePrevious(value, initial?) {
const ref = useRef({target: value, previous: initial});
if (ref.current.target !== value) {
// The value changed.
ref.current.previous = ref.current.target;
ref.current.target = value;
}
return ref.current.previous;
}
Top comments (1)
Is it safe to set ref outside useEffect? the docs says different: "Unless you’re doing lazy initialization, avoid setting refs during rendering"