The Usestate Set Method Is Not Reflecting a Change Immediately

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



Leave a reply



Submit