I'm reading the React Documentation and there is a topic that I didn't understand very well:
https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
function Counter() {
const [count, setCount] = useState(0);
const prevCountRef = useRef();
useEffect(() => {
prevCountRef.current = count;
});
const prevCount = prevCountRef.current;
return <h1>Now: {count}, before: {prevCount}</h1>;
}
Demo:
https://codesandbox.io/s/get-previous-state-ref--hook-faq-w0f3k?file=/src/App.js
I'd like a better explanation about this. Kind, how it's works?. Thanks
CodePudding user response:
There's three pieces here. A state, a ref, and an effect.
A state is a value that is remembered between renders, and it re-renders it's component when changed.
A reference (or ref) is a value that persists between renders like state does, but unlike state it's not watched for any changes and can be mutated freely. Changes to refs never cause renders.
An effect is simply a function that runs after a render, or after a render in one of its dependencies has changed since the previous render.
So putting that together here's what happens:
const [count, setCount] = useState(0);
Here a state is declared. Calling setCount
with a new value will cause the component to render, and when it does, count
will have the value that was set.
const prevCountRef = useRef();
Then declare the ref. This will hold a reference to the previous count value. Right now it no value (undefined
), which makes sense considering there is no previous value when the component first renders.
useEffect(() => {
prevCountRef.current = count;
});
Now declare an effect which runs after every render (you can tell this because it has no dependencies (would be the second argument to useEffect()
). When that runs it sets the current value of prevCountRef
to whatever the count is.
So, on the first render, in pseudo code:
// render starts
count // 0
prevCountRef.current // undefined
// render finishes
effect runs {
prevCountRef.current is set to 0
}
So when the render is happening the count
state is 0
and the previous count ref is undefined
.
Second render:
setCount(1) // triggers the second render
// second render starts
count // 1
prevCount.current // 0
// second render finishes
effect runs {
prevCount.current is set to 1
}
So as you can see, during the render you always have the current count as as state, and the previous count as the ref. This works because the effect that sets the refs value always runs after the render is done, which allows it to be whatever the previous value was.
CodePudding user response:
You can use componentDidUpdate to get the prev props and state. When you extend React.Component, it will call componentDidUpdate after each render. You define the function, and React will pass the prev props and prev state to you.
https://reactjs.org/docs/react-component.html#componentdidupdate
CodePudding user response:
useEffect
is called just after the component render.
The first time the component render prevCount is undefined
because useEffect has not been called yet.
pre-render:
1) value: 0, prevCount: undefined
post-render: useEffect is called:
2) value: 0, prevCount: 0
useRef
don't cause a new rendering, thus the component is not updated. refCount will be shown as undefined.
when you change the count value the component gets re-render:
pre-render:
3) value: 1, prevCount: 0
useEffect is not called yet.
post-render:
4) value: 1, prevCount: 1
useEffect is called, prevCount increased but the component is not updated so prevCount will be shown the the value = 0;