I'm using useRef
to hold the latest value of a prop so that I can access it later in an asynchronously-invoked callback (such as an onClick handler). I'm using a ref instead of putting value
in the useCallback dependencies list because I expect the value will change frequently (when this component is re-rendered with a new value
), but the onClick handler will be called rarely, so it's not worth assigning a new event listener to an element each time the value changes.
function MyComponent({ value }) {
const valueRef = useRef(value);
valueRef.current = value; // is this ok?
const onClick = useCallback(() => {
console.log("the latest value is", valueRef.current);
}, []);
...
}
The documentation for React Strict Mode leads me to believe that performing side effects in render()
is generally unsafe.
Because the above methods [including class component
render()
and function component bodies] might be called more than once, it’s important that they do not contain side-effects. Ignoring this rule can lead to a variety of problems, including memory leaks and invalid application state.
And in fact I have run into problems in Strict Mode when I was using a ref to access an older value.
My question is: Is there any concern with the "side effect" of assigning valueRef.current = value
from the render function? For example, is there any situation where the callback would receive a stale value (or a value from a "future" render that hasn't been committed)?
One alternative I can think of would be a useEffect
to ensure the ref is updated after the component renders, but on the surface this looks unnecessary.
function MyComponent({ value }) {
const valueRef = useRef(value);
useEffect(() => {
valueRef.current = value; // is this any safer/different?
}, [value]);
const onClick = useCallback(() => {
console.log("the latest value is", valueRef.current);
}, []);
...
}