I want to print the current and previous value of a state, I have a piece of code that does the job
function App() {
const [value, setValue] = useState("");
const prevValue = useRef('')
useEffect(() => {
prevValue.current = value;
}, [value]);
return (
<div>
<input
value={value}
onChange={e => setValue(e.target.value)}
/>
<div>
Curr Value: {value}
</div>
<div>
Prev Value: {prevValue.current}
</div>
</div>
);
}
But the problem with it is if I have some other state that is being set through, say, a button, it will cause the prev value to be same as current value. I'm looking for a way to prevent this, can someone please help?
Thanks.
Updating the ref
with useEffect
works for a single render, because the ref
is updated after the content has been rendered.
As you can see in here, the useEffect
is triggered when value changes. This means that at the end of each render cycle, prevValue.current
equals value
.
useEffect(() => {
prevValue.current = value;
}, [value]);
If another render is triggered by an unrelated update, the ref
is already equal to the current value
, and both are re-rendered.
To always maintain the ref
one step behind the value
, use an updater function when setting the state. The updater function is called with the previous state, that you can store in the ref
. Return the new state from the function to update the state.
The the example, you can see that the the ref always equals to the previous value, even if another update (clicking the button) causes a re-render:
const { useState, useRef } = React;
function App() {
const [anotherValue, setAnotherValue] = useState(0);
const [value, setValue] = useState('');
const prevValue = useRef('');
const onChange = e => {
const newVal = e.target.value;
// use an updater function
setValue(prev => {
prevValue.current = value; // set the previous value the the ref
return newVal; // return the updated value to the state
});
};
return (
<div>
<input
value={value}
onChange={onChange}
/>
<div>
Curr Value: {value}
</div>
<div>
Prev Value: {prevValue.current}
</div>
<button onClick={() => setAnotherValue(v => v +1)}>
Another value: {anotherValue}
</button>
</div>
);
}
ReactDOM
.createRoot(root)
.render(<App />);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>