How do we know when a React ref.current value has changed?
Problem:
We can normally check with props when the ref.current value has changed.
componentDidUpdate(oldProps) {
if (oldProps.foo !== this.props.foo) {
console.log('foo prop changed')
}
}
In this article, we will learn how do we know when a React ref.current value has changed?
with example.
Solution:
The official react document recommends we should use callback refs to detect ref value change. I will explain to you both hooks and the class component.
Class component:
export class App extends React.Component {
state = { ref: null, ... };
onRefChangeHandler = node => {
// same as Hooks example, re-render on changes
this.setState({ ref: node });
};
render() {
return <div ref={this.onRefChangeHandler}>Hello world</div>;
}
}
Note: when ref changes useRef does not notify. Here is a test case that re-adds a node and drops a node while triggering onRefChanges callback.
const App = () => {
const [ref, setRef] = useState(null);
const [removed, remove] = useState(false);
useEffect(() => {
setTimeout(() => remove(true), 5000); // drop after 3 sec
setTimeout(() => remove(false), 3000); // ... and mount it again
}, []);
const onRefChangeHandler = useCallback(node => {
console.log("ref changes:", node);
setRef(node);
}, []);
return !removed && <div ref={onRefChangeHandler}>Hello, world</div>;
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.1/umd/react.production.min.js" integrity="sha256-vMEjoeSlzpWvres5mDlxmSKxx6jAmDNY4zCt712YCI0=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.1/umd/react-dom.production.min.js" integrity="sha256-QQt6MpTdAD0DiPLhqhzVyPs1flIdstR4/R7x4GqCvZ4=" crossorigin="anonymous"></script>
<script> var {useState, useEffect, useCallback} = React</script>
<div id="root"></div>
Hooks:
export function App() {
const onRefChangeHandler = useCallback((node) => {
if (node === null) {
// DOM node referenced by ref has been unmounted
} else {
// DOM node referenced by ref has changed and exists
}
}, []);
return <div ref={onRefChangeHandler}>Hello World!</div>;
}
Here, To prevent the double calling of ref callback with null we used useCallback. But by storing the current node using useState you can also trigger re-render on change.
const [domNode, setDomNode] = useState(null);
const onRefChangeHandler = useCallback((node) => {
setDomNode(node); // it will trigger re-render on changes
}, []);
Thank you for reading this article. If you have any confusion please comment down below.