Reputation: 181
People use useRef to save latest value like this code
function MyComponent({ value }) {
const valueRef = useRef();
useEffect(() => {
valueRef.current = value;
});
}
I know useEffect needs for concurrent mode.
and useEffect is executed in the order of the definition
function MyComponent({ value }) {
useEffect(() => {
console.log('log1');
});
useEffect(() => {
console.log('log2');
});
}
// result is
// log1
// log2
so in the below code, log1 is printed with old value and log2 is printed with new value
function MyComponent({ value }) {
const valueRef = useRef();
useEffect(() => {
console.log('log1', valueRef.current);
});
useEffect(() => {
valueRef.current = value;
});
useEffect(() => {
console.log('log2', valueRef.current);
});
}
I think it's weird because the value is different according to the position.
What is the right way to use useRef to reference latest value? (FYI I know it's better to use deps than to use useRef)
Upvotes: 18
Views: 107840
Reputation: 1473
Another approach is change ref value after if condition.
const valueRef = useRef();
useEffect(() => {
console.log('log1', valueRef.current);
});
if(valueRef.current !== value) {
valueRef.current = value;
};
useEffect(() => {
console.log('log2', valueRef.current);
});
Upvotes: 4
Reputation: 4446
To get the latest value from all code positions (render, useEffect
body, disposal function body), you have to use at least two useRef
s.
Here is the code
export const usePrevRef = value => {
const currentRef = useRef()
const prevPref = useRef()
prevPref.current = currentRef.current
currentRef.current = value
return prevPref
}
If you use one useRef
, and place the ref.current = value
update in ③(or⑤), then the value won't be correct if called from ④and⑥(or⑥).
I wrote a blog on this. Please feel free to check.
Upvotes: 1
Reputation: 7671
It really depends on what you mean by latest value, your code does store latest value to valueRef.current
.
const valueRef = useRef();
useEffect(() => {
console.log('log1', valueRef.current);
});
useEffect(() => {
valueRef.current = value;
});
useEffect(() => {
console.log('log2', valueRef.current);
});
If you do want to have a more "stable" value, then you should use setState
.
const valueRef = useRef();
const [value, setValue] = useState(null);
useEffect(() => {
setValue(1)
console.log('log1', valueRef.current);
});
useEffect(() => {
// value is still 1
valueRef.current = value;
});
useEffect(() => {
// value is still 1
console.log('log2', valueRef.current);
});
IMHO, useRef
is a very difficult topic, it was designed for Dom
ref initially. But then people find it useful when it comes to decouple the variable from the rendering state/prop. You can't actually say useRef
always store the latest value, it actually still store the regular value, except it won't trigger re-render, since the reference to this ref
is fixed after initialization (only ref.current
is changing).
Upvotes: 17
Reputation: 202706
The idiomatic way is to store some "current" value for the next render and retrieve the current ref value (the previous value). Hooks FAQ: How to get the previous props or state
const prevValueRef = useRef();
useEffect(() => {
prevValueRef.current = value; // cache current value for next render
});
const prevValue = prevValueRef.current; // get previous value from last render
Running sandbox demo
Upvotes: 1