如何从localStorage获取用户信息并解决首次渲染无数据问题
问题详情
登录后首次渲染Navbar组件时,拿不到当前用户的username和_id,导航栏没法显示用户名,点个人资料的跳转链接也没用;但刷新页面后就能正常获取信息。
相关代码
Navbar.js
const Navbar = () => { const {user} = useSelector((state) => state.user) const user2 = JSON.parse(user).username const id = JSON.parse(user)._id return ( <Typography marginRight={2} sx={{color: {xs: 'white', md: 'black'}}}> Hello {user2} </Typography> <Link to={`/edit_user/${id}`} style={{textDecoration: 'none', color: 'inherit'}}> <MenuItem onClick={handleCloseUserMenu}> {settings[0]} </MenuItem> </Link> ) }
userSlice.js
import {createSlice} from '@reduxjs/toolkit' const user = localStorage.getItem("token") export const userSlice = createSlice({ name: 'user', initialState : { user: user ? user : null, isError: false, isSuccess: false, isLoading: false, message: '' }, reducers: {getUserStart: (state) =>{ state.isLoading = true; state.isError = false; }, getUserSuccess:(state, action) =>{ state.isLoading = true; state.isSuccess = true; state.user = action.payload; }, getUserFailure: (state, action) =>{ state.isLoading = false; state.isError = true; state.message = action.payload state.user = null } } })
apiCalls.js
export const getUser = async (dispatch,id) =>{ getUserStart() try { const getUser = await publicRequest.get('/users/find/'+id) dispatch(getUserSuccess(getUser.data)) } catch (error) { dispatch(getUserFailure()) } } export const loginUser = async (userData, dispatch) =>{ dispatch(loginStart()) try { const res = await publicRequest.post('/auth/login', userData) localStorage.setItem('token', JSON.stringify(res.data)) dispatch(loginSuccess(res.data)) } catch (error) { const message = "Wrong Username or Email " dispatch(loginFailure(message)) } }
问题现象
- localStorage内容:已存储包含
username和_id的用户信息 - 首次渲染结果:导航栏没显示用户名,个人资料跳转链接无效
- 刷新后结果:导航栏正常显示用户名,跳转链接可正常访问
解决办法
1. 修正redux初始状态的存储格式
你现在userSlice里初始状态直接存了localStorage拿的字符串,但登录成功后存的是对象,这就导致首次登录后redux里的user是对象,Navbar里强行JSON.parse对象肯定报错。改一下userSlice的初始状态:
const user = localStorage.getItem("token") export const userSlice = createSlice({ name: 'user', initialState : { // 把字符串解析成对象再存 user: user ? JSON.parse(user) : null, isError: false, isSuccess: false, isLoading: false, message: '' }, // 其他代码不变 })
2. Navbar里加空值判断,避免报错
万一user还没加载出来(比如登录请求还在pending),直接取属性会崩,加个可选链操作符:
const Navbar = () => { const {user} = useSelector((state) => state.user) const username = user?.username || '' const userId = user?._id || '' return ( <Typography marginRight={2} sx={{color: {xs: 'white', md: 'black'}}}> Hello {username} </Typography> {/* 只有userId存在时才渲染链接 */} {userId && ( <Link to={`/edit_user/${userId}`} style={{textDecoration: 'none', color: 'inherit'}}> <MenuItem onClick={handleCloseUserMenu}> {settings[0]} </MenuItem> </Link> )} ) }
3. 修正userSlice里的状态错误
你看getUserSuccess里把isLoading设成true了,这明显不对,请求成功后应该把loading关掉:
getUserSuccess:(state, action) =>{ state.isLoading = false; // 这里改成false state.isSuccess = true; state.user = action.payload; },
4. 确认所有action都导出了
别漏了导出loginStart这些action,不然apiCalls里调用会报错:
export const { getUserStart, getUserSuccess, getUserFailure, loginStart, loginSuccess, loginFailure } = userSlice.actions
内容的提问来源于stack exchange,提问作者Stykgwar
相关产品推荐
相关产品推荐

