The useState set method does not reflect a change immediately
The useState set method does not reflect a change immediately because the state update using the useState hook is asynchronous for some performance reasons. Also, the state values used by functions are based on their current closures. The changes in the state will only reflect in the component after re-render by which a new closure is created.
In the below example, when the user clicks on the button first time, the state message
in console.log(message);
refers to the value No message
. Because the old closure still holds the original value until the component is re-renders. After React re-renders the component, a new closure is created with the updated state value of Hello World!
in the message
state.
import React, { useState } from 'react';
export default function App() {
const [message, setMessage] = useState('No message');
const showMessage = () => {
setMessage("Hello World!");
console.log(message); // output: "No message" on first button click
}
return (
<>
<button onClick={showMessage}>Show Message</button>
</>
);
}
Even if you add a setTimeout function in the above example, though the setTimeout callback function will run after some time by which the re-render would have happened, the setTimeout will still use the value from its previous closure and not the updated one. So It will log the previous state value No message
.
const showMessage = () => {
setMessage("Hello World!");
setTimeout(()=>{
console.log(message);
}, 2000);
}
Methods to solve the usestate set method do not reflect a change immediately
Use the useEffect hook
If you want to perform some actions on the state update, you can use the useEffect hook. Using useEffect hook is the easiest solution for the above issue.
import React, { useState, useEffect }from 'react';
export default function App() {
const [message, setMessage] = useState('');
useEffect(()=>{
console.log(message);
}, [message])
const showMessage = () => {
setMessage("Hello World!");
}
return (
<>
<button onClick={showMessage}>Show Message</button>
</>
);
}
In the above example, we have used useEffect hook with the message state as its dependency. So when the message state gets changed, the function inside the useEffect will get invoked.
The useEffect Hook is used to perform side effects in a function component. Some examples of side effects are data fetching, and manually changing the DOM in React components. If you’re familiar with React class lifecycle methods, it is similar to componentDidMount, componentDidUpdate, and componentWillUnmount combined. Multiple dependencies can be passed into useEffect as an array. When any of the values in the array change, the callback function inside the useEffect will get executed.
Use a mutable reference useRef
Another solution to the above issue is to use use a mutable reference useRef().
if you don't need a state and only want to remember the value, you can use a mutable reference of useRef(). Updating a ref doesn't trigger the re-render of the React component.
import React, { useRef }from 'react';
export default function App() {
const message = useRef('');
const showMessage = () => {
message.current = "Hello World!";
console.log(message.current) ;
}
return (
<>
<button onClick={showMessage}>Show Message</button>
</>
);
}
In the above example, we used useRef hook for storing the value. The value inside the ref can be accessed using the current property.
When you mutate the ref.current property, React does not re-render your component. React is not aware when you change its value because a ref is a plain JavaScript object. The useRef will return the same value after the component every re-render and you can use its current property to store some values and can read it later.
Conclusion
To solve useState set method does not reflect a change immediately we can use of useEffect hook with the state as its dependency and actions to be performed inside the useEffect. Another solution is to use use a mutable reference useRef(). You can use useRef hook for storing the value and no need re-render when you mutate the ref.current property.
On datainfinities.com, Read articles all around JavaScript, React, Node.js, PHP, Laravel, and Shopify.
Related Blogs
How to Fix - React Hook useEffect has a missing dependency
'react-scripts' is not recognized as an internal or external command
How to Integrate Custom Build CKEditor5 with React
Get the current route using React Router
Create a Back button with React Router
node: --openssl-legacy-provider is not allowed in NODE_OPTIONS
useHref() may be used only in the context of a Router component
How to fix npm ERR! Missing script: "start"
Explore All Blogs