The useState set method is not reflecting a change immediately
Much like .setState()
in class components created by extending React.Component
or React.PureComponent
, the state update using the updater provided by useState
hook is also asynchronous, and will not be reflected immediately.
Also, the main issue here is not just the asynchronous nature but the fact that state values are used by functions based on their current closures, and state updates will reflect in the next re-render by which the existing closures are not affected, but new ones are created. Now in the current state, the values within hooks are obtained by existing closures, and when a re-render happens, the closures are updated based on whether the function is recreated again or not.
Even if you add a setTimeout
the function, though the timeout 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.
setMovies(result);
console.log(movies) // movies here will not be updated
If you want to perform an action on state update, you need to use the useEffect
hook, much like using componentDidUpdate
in class components since the setter returned by useState
doesn't have a callback pattern
useEffect(() => {
// action on update of movies
}, [movies]);
As far as the syntax to update state is concerned, setMovies(result)
will replace the previous movies
value in the state with those available from the async request.
However, if you want to merge the response with the previously existing values, you must use the callback syntax of state updation along with the correct use of spread syntax like
setMovies(prevMovies => ([...prevMovies, ...result]));
useState set method not reflecting change immediately (solution suggested in Stackoverflow not working)
When you call setSubtotal
, the subtotal
variable does not get updated instantly. That means that your calls to computeTaxes
and computeTotal
are operating on the old value.
This would be fine if your effect is called on every update to the state or the props, but this definition:
useEffect(() => {
computePriceSummary();
}, []);
means that this effect is only called once. In order to fix it, use something like this:
useEffect(() => {
computePriceSummary();
}, [subtotal, taxes, total]);
The component will be re-rendered on each change of your state variables, and by having them in the dependencies of the effect, that effect will be retriggered properly.
Adding a second effect (the one where you use console.log
) will not cause the first effect to be re-run in your case.
useState set method not reflecting change immediately
Here there are 2 ways to solve your issue.
Store error in local variable and use those variables to setState and check noError.
const onSubmit = async(data) = > {
const nameErr = nameValidation(data.name);
const phoneErr = nameValidation(data.phoneNumber);
const emailErr = nameValidation(data.email);
const messageErr = nameValidation(data.message);
setNameError(nameErr);
setphoneError(phoneErr);
setEmailError(emailErr);
setMessageError(messageErr);
let noErrors = (!nameErr && !phoneErr && !emailErr && !messageErr);
// rest of your code
}
use useEffect to calculate noErrors
const onSubmit = async(data) = > {
setNameError(nameValidation(data.name));
setphoneError(phoneNumberValidation(data.phoneNumber));
setEmailError(emailValidation(data.email));
setMessageError(messageValidation(data.message));
}
useEffect(() => {
const submitForm = async () => {
let noErrors = (!nameErr && !phoneErr && !emailErr && !messageErr);
if (noErrors) {
try {
// const templateParams = {
// name: data.name,
// email: data.email,
// number: data.phoneNumber,
// message: data.message,
// };
// await emailjs.send(
// process.env.REACT_APP_SERVICE_ID,
// process.env.REACT_APP_TEMPLATE_ID,
// templateParams,
// process.env.REACT_APP_USER_ID
// );
reset();
toastifySuccess();
} catch (e) {
console.log(e);
}
}
}
submitForm();
},[nameError, phoneError, emailError, messageError])
React useState not updating on first click
as state updates are async, you may see your state value updating by adding building to a useEffect dependency, thus causing it to fire whenever the value of building changes.
const [building, setBuilding] = useState(0);
useEffect(() => {
console.log(building);
}, [building]);
return (
<button
title="tester"
onClick={() => {
setBuilding(1);
}}
>
test
</button>
);
Why useState is not updating immediately after button click?
In react, updating state is asynchronous. Updated value is only available during the next render. Meaning, updating & them immediately console logging will give you the old state.
setTest(true);
console.log(test); //test is still false
You can print the state value to see the update -
return(
<>
<button onClick={fun}>Test</button>
{test}
</>
}
React hooks useState not updating the state
You can use useEffect for that and pass the state as dependency, so every time users state get change it would get invoke.
useEffect(() => {
console.log(users);
}, [users])
useState set method inside useEffect hook not updating till refreching the page
Yeah, looks like each useToken
hook maintains its own state. The setToken
Header
is using is from the useToken
whereas nothing updates the token
state of the useToken
hook that useUsers
is using, so the useEffect
hook won't retrigger.
What you might try doing is to return the token
and setToken
from the useToken
hook that useUser
is using so there's only the one instance.
export const useUser = () => {
const [token, setToken] = useToken();
const getPayloadFromToken = token => {
console.log(token);
const encodedPayload = token.split('.')[1];
console.log(JSON.parse(atob(encodedPayload)), ': encodedPayload');
return JSON.parse(atob(encodedPayload));
}
const [user, setUser] = useState(() => {
// console.log('token from user useState', token , '***');
if (!token) {
console.log(token);
return {};
};
// console.log(getPayloadFromToken(token));
return getPayloadFromToken(token);
});
useEffect( ()=>{
console.log('token from user useEffect', token , '***');
if (!token) {
console.log('user will become null');
setUser({});
} else {
console.log(' useEffect ');
setUser(getPayloadFromToken(token));
}
}, [token]);
return [user, token, setToken];
}
...
export const HeaderHelper = (props) => {
const [user, token, setToken] = useUser();
const navigate = useNavigate();
return (
<Header
{...props}
navigate={navigate}
token={token}
setToken={setToken}
user={user}
/>
);
}
useState set call not reflecting change immediately prior to first render of app
Unless you are wanting to partially render when you get the user ID, and then get the access level. There is no reason to have multiple useState's / useEffect's.
Just get your user and then get your access level and use that.
Below is an example.
const [user, setUser] = useState(null);
const checkUserAccess = async (empid) => {
const response = await fetch("http://localhost:4200/get-valid-users");
const allUsers = await response.json();
const validIds = allUsers.map(({ id }) => id);
const isAuthorised = validIds.includes(empid);
return isAuthorised;
}
const getUser = async () => {
try {
const response = await fetch("http://localhost:4200/get-user");
const theId= await response.json();
const access = await checkUserAccess(theId);
setUser({
theId,
access
});
} catch (err) {
console.error(err.message);
}
}
useEffect(() => {
getUser();
}, []);
if (!user) return <div>Loading</div>;
return <>{user.theId}</>
Related Topics
Sorting Options Elements Alphabetically Using Jquery
How to Select Multiple Files With ≪Input Type="File"≫
Alternative For Deprecated Svg Pathseglist
Getcurrentposition() and Watchposition() Are Deprecated on Insecure Origins
How to Implement Dom Data Binding in JavaScript
How to Disable Scroll Without Hiding It
How to Set Focus on an Element in an HTML Form Using JavaScript
Upload Progress Indicators For Fetch
How to Display JavaScript Variables in a HTML Page Without Document.Write
Referenceerror: $ Is Not Defined
Strange Behavior When Iterating Over Htmlcollection from Getelementsbyclassname
How to Select Nth Line of Text (Css/Js)
Restart Animation in Css3: Any Better Way Than Removing the Element