简体   繁体   中英

React useState hook not updating within async useEffect

I want to overwrite user with the object I saved in localStorage, but its not working.

Note, component is called Index because I'm using next.js

import React, { useState, useEffect } from 'react';
import { loadUser } from '../utils/user';

const Index = () => {
  const [ user, setUser ] = useState({});

  async function restore(){
    const loadedUser = await loadUser();
    console.log(loadedUser);                    // correct - {userId: 4124783261364}
    setUser(loadedUser); 
    console.log(user);                          // was not updated - {}
  };

  useEffect(() => {
    restore();
  }, [0])

  return (<></>);
};

export default Index;

Issues

  • If you want to run an effect and clean it up only once (on mount and unmount ), you can pass an empty array ( [] ) ( not [0] ), as a second argument. This tells React that your effect doesn't depend on any values from props or state, so it never needs to re-run .
  • 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 . That's why console.log(user); doesn't show updated value next to setUser(loadedUser);

Solution

  const restore = async () => {
    const loadedUser = await loadUser();
    console.log(loadedUser);                    // correct - {userId: 4124783261364}
    setUser(loadedUser); 
    console.log(user);                          // user is not updated here, but will be
  };

  useEffect(() => {
    restore();
  }, []);

Similar Situation

This is away from your problem since you just need to load user from local storage just one time. But when loadUser() returns changing results by time so need to update user real time, you should use useCallback .

  const updateUser = useCallback(async () => {
    const loadedUser = await loadUser();
    setUser(loadedUser); 
  }, []);

  useEffect(() => {
    updateUser();
  }, [updateUser]);

Try something like this:

// Assuming your loadUser() functions is set like the line below
const loadedUser = {userID: '513216351354'};


const Index = () => {

function restore(){
  console.log("Loaded user is " + loadedUser.userID);       // Loaded user is 513216351354
  setUser(loadedUser.userID); 
  console.log("User is " + user);                          // User is 513216351354
};

useEffect(() => {
  restore();
}, [])

return (<></>);
}

export default Index;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM