我开始学习React,我有一个问题,有关检查用户的登录状态。我通过从localStorage获取用户信息来检查用户的登录状态。如果用户已登录,我将把用户重定向回主页。一切都很好,但如果用户关闭选项卡并返回,如果用户先前登录然后注销,当单击按钮转到认证页面时,即使url设置为"/auth"
,在这种情况下,似乎loginUser
的值是错误的,并且Route呈现<Home />
而不是<Auth />
。我不明白为什么它会发生在用户关闭标签并返回的情况下。
这是我的App.js代码。
const App = () => {
const loginUser = JSON.parse(localStorage.getItem("profile"));
const dispatch = useDispatch();
// I use redux's global state to store user info and render components corresponding to that state.
// So when starting the app check the local storage and sync it with the redux state
useEffect(() => {
if (loginUser) {
dispatch({ type: AUTH, payload: loginUser });
}
}, []);
return (
<>
<Helmet>
<meta
http-equiv="Cross-Origin-Opener-Policy"
content="same-origin-allow-popups"
/>
</Helmet>
<Router>
<Container style={{ marginBottom: "150px" }} maxWidth="xl">
<NavBar />
<Routes>
<Route path="/" exact element={<Navigate to={"/posts"} />} />
<Route path="/posts" exact element={<Home />} />
<Route path="/posts/search" exact element={<Home />} />
<Route path="/posts/:id" exact element={<PostDetails />} />
<Route path="/auth" element={!loginUser ? <Auth /> : <Home />} />
</Routes>
</Container>
</Router>
</>
);
};
字符串
下面是我的Navbar
,它根据我用来存储登录用户信息的状态“profile”呈现Login
和Logout
按钮。
export default function NavBar() {
const classes = useStyle();
const navigate = useNavigate();
const dispatch = useDispatch();
const [messageApi, contextHolder] = message.useMessage();
const user = useSelector((state) => state.profile);
const logout = (e) => {
e.preventDefault();
dispatch({ type: LOGOUT });
messageApi.success("Logged out.");
};
return (
<>
{contextHolder}
<AppBar className={classes.appBar} position="static" color="inherit">
<div className={classes.brandContainer}>
<Typography
to="/"
component={Link}
className={classes.heading}
variant="h2"
align="center"
>
My app
</Typography>
<img
className={classes.image}
src={memoriesImg}
alt="memories"
height="60"
/>
</div>
<Toolbar>
{Object.keys(user).length !== 0 ? (
<div className={classes.profile}>
<Avatar
className={classes.purple}
alt={user?.name}
src={user?.picture}
>
{user?.name?.charAt(0)}
</Avatar>
<Typography className={classes.userName} variant="h6">
{user?.name}
</Typography>
<Button
onClick={(e) => logout(e)}
variant="contained"
className={classes.logout}
color="secondary"
>
Logout
</Button>
</div>
) : (
<Button
component={Link}
to="/auth"
variant="contained"
color="primary"
>
Login
</Button>
)}
</Toolbar>
</AppBar>
</>
);
}
型
以下是用户登录和注销时reducer内部发生的情况
export default (profile = {}, action) => {
switch (action.type) {
case AUTH:
localStorage.setItem("profile", JSON.stringify({ ...action.payload }));
return { ...profile, ...action.payload.profile };
case LOGOUT:
localStorage.removeItem("profile");
return {};
case "TEST":
console.log("dispatch success TEST from axios");
return profile;
default:
return profile;
}
};
型
我还录制了一个简短的视频,其中第一部分显示了当我登录,注销,并正常进入认证页面。但是,当我关闭标签并打开一个新的标签,然后注销后,我不能去认证页面了。
https://somup.com/c0iIQRzu64
我希望有人来检查,如果它是合理的,我存储用户信息,并处理它这样。如果哪里出了什么问题。
1条答案
按热度按时间8iwquhpp1#
问题
基本上,问题是redux状态没有很好地耦合到localStorage。当身份验证状态更改时,
App
组件不会重新呈现。以下是事件的时间轴,因为我远,我可以告诉从视频:
App
挂载,loginUser
从localStorage读取。由于loginUser
是falsey,因此不会将任何操作分派到存储区,并且用户未经身份验证。1.用户在
NavBar
中单击“登录”,应用程序导航到"/auth"
,由于loginUser
是错误的,因此呈现Auth
组件。1.用户身份验证成功,应用程序导航到
"/posts"
。1.用户在
NavBar
中单击“注销”,并成功注销。更新了redux状态,并清除了localStorage。NavBar
重新呈现并再次显示“Log In”按钮。1.用户在
NavBar
中单击“登录”,应用程序导航到"/auth"
,由于loginUser
(* 本地副本 ) 仍然 * 错误,因此呈现Auth
组件。1.用户身份验证成功,应用程序导航到
"/posts"
。1.关闭活动选项卡并打开一个新选项卡,挂载
App
并从localStorage读取loginUser
,由于用户已通过身份验证,因此loginUser
是真实的,并更新了redux存储。NavBar
被重新渲染,并且“注销”按钮被渲染。1.用户在
NavBar
中点击“注销”,成功注销。更新了redux状态,并清除了localStorage。NavBar
重新呈现并再次显示“Log In”按钮。1.用户在
NavBar
中单击“Log In”,应用导航到"/auth"
,由于loginUser
(* 本地副本 ) 仍然是 * truthy,因此呈现Home
组件。应用程序“卡”在“已验证”状态。要解决这个问题,Redux状态应该从localStorage初始化,
App
中的loginUser
应该像NavBar
组件中一样从store中选择状态。这样,当Redux store中的auth状态更新时,App
将使用当前选定的redux状态值重新呈现。示例如下:
个字符