React useState 钩子不在异步 useEffect 中更新
React useState hook not updating within async useEffect
我想用我保存在 localStorage 中的对象覆盖 user,但它不起作用。
注意,组件被称为 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;
尝试这样的事情:
// 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;
问题
- 如果你想运行一个效果并清理它只一次(在mount和unmount),可以传一个空数组(
[]
) (不是[0]
) ,作为第二个参数。这告诉 React 你的效果 不依赖于 props 或 state 的任何值,所以它 never 需要 re-run.
- 很像Class组件中的setState通过扩展React.Component或React.PureComponent创建的,状态更新使用[=提供的updater 26=]useState hook也是异步的,不会立即体现。这就是 为什么
console.log(user);
没有在 setUser(loadedUser);
旁边显示更新值
解决方案
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();
}, []);
类似情况
这远离您的问题,因为您只需要一次从本地存储加载用户。但是当loadUser()
returns 改变结果需要实时更新用户时,你应该使用useCallback
.
const updateUser = useCallback(async () => {
const loadedUser = await loadUser();
setUser(loadedUser);
}, []);
useEffect(() => {
updateUser();
}, [updateUser]);
我想用我保存在 localStorage 中的对象覆盖 user,但它不起作用。
注意,组件被称为 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;
尝试这样的事情:
// 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;
问题
- 如果你想运行一个效果并清理它只一次(在mount和unmount),可以传一个空数组(
[]
) (不是[0]
) ,作为第二个参数。这告诉 React 你的效果 不依赖于 props 或 state 的任何值,所以它 never 需要 re-run. - 很像Class组件中的setState通过扩展React.Component或React.PureComponent创建的,状态更新使用[=提供的updater 26=]useState hook也是异步的,不会立即体现。这就是 为什么
console.log(user);
没有在setUser(loadedUser);
旁边显示更新值
解决方案
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();
}, []);
类似情况
这远离您的问题,因为您只需要一次从本地存储加载用户。但是当loadUser()
returns 改变结果需要实时更新用户时,你应该使用useCallback
.
const updateUser = useCallback(async () => {
const loadedUser = await loadUser();
setUser(loadedUser);
}, []);
useEffect(() => {
updateUser();
}, [updateUser]);