简体   繁体   English

React useState 钩子未在异步 useEffect 内更新

[英]React useState hook not updating within async useEffect

I want to overwrite user with the object I saved in localStorage, but its not working.我想用我保存在 localStorage 中的对象覆盖用户,但它不起作用。

Note, component is called Index because I'm using next.js注意,组件被称为Index因为我使用的是 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.如果您只想运行效果并仅将其清理一次(在mountunmount 上),您可以传递一个空数组 ( [] )(不是[0] )作为第二个参数。 This tells React that your effect doesn't depend on any values from props or state, so it never needs to re-run .这告诉 React 你的 effect不依赖于来自 props 或 state 的任何值,所以它永远不需要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 .继承 React.Component 或 React.PureComponent 创建的Class 组件中的 setState 非常相似,使用useState hook提供的 updater 进行状态更新也是异步的不会立即反映出来 That's why console.log(user);这就是为什么console.log(user); doesn't show updated value next to setUser(loadedUser);setUser(loadedUser);旁边不显示更新的值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 .但是当loadUser()按时间返回变化的结果因此需要实时更新用户时,您应该使用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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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