Home > Blockchain >  Explanation: Get previous state
Explanation: Get previous state

Time:12-08

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;

  • Related