Avoid Listening for Ref Changes in useEffect – Use a Ref Callback Instead
When working with refs in React, it's crucial to understand how updates to a ref's current property behave. A common mistake developers make is trying to use useEffect to track changes in a ref. However, React does not notify about changes in ref.current, making this approach ineffective.
Why Listening for Ref Changes in useEffect Doesn't Work
Consider the following example:
function App() {
const [height, setHeight] = React.useState(0);
const elementRef = React.useRef(null);
React.useEffect(() => {
if (elementRef.current) {
setHeight(elementRef.current.offsetHeight);
}
}, [elementRef.current]); // ❌ Incorrect dependency
return <div ref={elementRef}></div>;
}
What's Wrong?
The Correct Approach: Using a Ref Callback
A better way to handle this is by using a ref callback with useCallback:
function App() {
const [height, setHeight] = React.useState(0);
const elementRef = React.useCallback(node => {
if (node !== null) {
setHeight(node.offsetHeight);
}
}, []);
return <div ref={elementRef}></div>;
}
Why This Works
By using a ref callback, you ensure proper handling of DOM element changes without unnecessary re-renders or stale values.