import { useRef, useState } from "react";
import "./styles.css";
function usePrevious(value) {
const currRef = useRef();
const previousValue = currRef.current;
currRef.current = value;
return previousValue;
}
export default function App() {
const [counter, setCounter] = useState(0);
const previousValue = usePrevious(counter);
return (
<div className="App">
<h1>{counter}</h1>
<h1>{previousValue}</h1>
<h2 onClick={() => setCounter((prev) => prev + 1)}>btn</h2>
</div>
);
}
I was trying an implementation for usePrevious
, but both the previousValue
and the counter
are the same values when the button is clicked for the first time, why?
I tried tracing it but I couldn’t reach to any explanation.
2
Answers
The reason you’re seeing the same value is that your app is wrapped in
StrictMode
, which causes components to render twice in development mode. This behavior is intentional and helps identify potential issues in your code. The function you’re referring to is deterministic, meaning that it produces the same result when called with the same arguments. Therefore, the value remains consistent across the two render cycles.In React, this double rendering in StrictMode is designed to ensure that components and functions handle state and side effects correctly and are resilient to unexpected behaviors. By observing how your components behave under these conditions, you can ensure that they work reliably and predictably.
It appears your
usePrevious
hook implementation isn’t updating the internal React ref as part of the React component lifecycle and theReact.StrictMode
component is surfacing the issue.The typical
usePrevious
hook recipe uses theuseEffect
hook to update the ref though.Example:
Oddly enough I’m able to reproduce the issue with your code in a running Codesandbox with your exact code copy/pasted in, but here in a running stack snippet your code runs exactly as expected.
I’d still suggest/recommend the version that uses the intentional side-effect to update the ref, i.e. the version using
useEffect
.