0

I have got an issue where I need to update the name in my useContext and then straight away check it against another part of my code. Although when I check it against another part the name value in the context is still empty.

So this is my context file...

export const UserContext = createContext();

function UserContextProvider(props) {

    const [user, setUser] = useState({
        name: '',
        email: ''
    });

    function updateUser(field, value) {
        return new Promise((resolve, reject) => {
            setUser((prevValue) => {
                return {...prevValue, [field]: value}
            })
            resolve();
        })
        
    }

    return (
        <UserContext.Provider value={{user, updateUser}}>
            {props.children}
        </UserContext.Provider>
    )
}

And this is what I want to run...

const { user, updateUser } = useContext(UserContext);    
    async function method(event) {
         event.preventDefault();

        await updateUser("name", "Shaun")
        console.log(user);
    }

I also tried with async and await but that didn't work either

I have re-produce the issue in my codesandbox here: https://codesandbox.io/s/youthful-smoke-fgwlr?file=/src/userContext.js

2 Answers2

0

await in await updateUser("name", "Shaun") is just wait for the Promise at return new Promise((resolve, reject) didn't await for setUser, setUser is asynchronous function (not a Promise). So if you want to check get latest user you need to check it in another useEffect in App.js

useEffect(() => {
  console.log(user);
}, [user]);
Tony Nguyen
  • 3,298
  • 11
  • 19
0

Simply put: you can't do it the way you think. Note that user is a const. Calling setUser within updateUser does not change the fact that user is still bound to the same value it was before. At no point during this execution of your component's render function is user being re-assigned (and if it were, you'd get an error because it is a const). user will not change until the next time your component is refreshed and useState is called again (which will be very shortly, considering you just called setUser).

That said, I'm not sure what use case would actually make sense to check it after calling setUser. You already know that the user's name should be Shaun, so if you need that value for something, you already have it; checking that it has been assigned to user isn't necessary or useful at all. If you expect your updateUser function to potentially make changes to the value you pass, and you need to validate that the value is correct, you should have your async function return the value. Then you can check that value after the promise resolves. That said, any check like that probably should exist within your updateUser function anyways; any attempt to check or validate it after calling setUser seems like an anti-pattern.

rfestag
  • 1,913
  • 10
  • 20
  • The value 'Shaun' was just an example people can understand better what I was trying to do. It is solved now. – Shaun Evans Jul 08 '20 at 14:28
  • I understand that. The accepted solution is in line with my explanation above. I was under the impression that you were trying to see the value after it changed within the useEffect hook that made the change. The second useEffect hook will execute after the component re-renders. Note that this *may* case multiple re-renders for the component, depending on what you do within the second useEffect. – rfestag Jul 09 '20 at 00:41