![](/img/trans.png)
[英]Conditional rendering in React Router with Private and Public Routes
[英]Restricted navigation React Router Dom - Private and Public routes
我需要制作一个区分经过身份验证和未经身份验证的用户的路由器系统。
我想要实现的是,经过身份验证的用户可以看到他们的仪表板和个人详细信息,但未经身份验证的用户只能看到登录页面、登录表单和注册表单。
我目前有上下文管理,所以我知道用户是否登录。 我只需要弄清楚所有重定向和路由相关的事情。
我的代码正在制作各种“奇怪”的东西。 我真的不知道我在哪里搞砸了。
这是所有路由发生的地方。 AppLayout
只是一个布局包装器,带有 header 和一个仅在登录时才可见的页脚。
const AppContent = () => (
<Router>
<Switch>
<PublicRoute component={() => (<h1>Landing page</h1>)} path='/' exact />
<PublicRoute component={LoginPage} path='/login' exact />
<PublicRoute component={() => (<h1>Register page</h1>)} path='/register' exact />
<PrivateRoute component={Home} path='/dashboard' exact />
<PrivateRoute component={Demo} path='/demo' exact />
<PrivateRoute component={Profile} path='/profile' exact />
<PublicRoute component={() => (<h1>not found</h1>)} path='*' />
<PrivateRoute component={() => (<h1>not found</h1>)} path='*' />
</Switch>
</Router>
);
const PublicRoute = ({ component: Component, ...rest }) => {
const { user, isLoading } = useContext(AuthContext);
if (isLoading) {
return (
<h1>Loading...</h1>
);
}
return (
<Route {...rest} render={(props) => (user ? <Redirect to='/dashboard' /> : <Component {...props} />)} />
);
};
const PrivateRoute = ({ component: Component, ...rest }) => {
const { user, isLoading } = useContext(AuthContext);
if (isLoading) {
return (
<h1>Loading...</h1>
);
}
return (
<Route
{...rest}
render={(props) => (user ? (
<AppLayout>
<Component {...props} />
</AppLayout>
) : <Redirect to='/login' />)}
/>
);
};
这是我管理身份验证上下文的地方。
const AuthStore = ({ children }) => {
const [token, setToken] = useState();
const [user, setUser] = useState();
const [isLoading, setIsLoading] = useState(false);
const setUserToken = async (userToken) => {
localStorage.setItem('token', userToken);
setToken(userToken);
try {
const decodedToken = jwtDecode(userToken);
const currentUserData = await AuthService.getUserData(decodedToken.username);
setUser(currentUserData);
} catch (error) {
console.log(error.name);
}
};
useEffect(() => {
setIsLoading(true);
const localToken = localStorage.getItem('token');
if (localToken) {
setUserToken(localToken);
}
setIsLoading(false);
}, []);
return (
<AuthContext.Provider value={{
user, token, setUserToken, setUser, isLoading,
}}
>
{children}
</AuthContext.Provider>
);
};
太感谢了。
我真正在寻找什么: 未经授权时:
/dashboard
时,重定向到/login
✅/login
✅/register
,重定向到它就好✅授权时:
/login
时,重定向到/dashboard
✅<PrivateRoute component={() => (<h1>not found</h1>)} path='*'
✅/profile
,重定向到它很好 ❌ ➡️ 它当前正在重新加载路由,显示登录页面,半秒后显示/dashboard
,但不显示/profile
根据React Router文档, <Switch>
组件的直接子级只能是 react-router-dom package 中的<Route>
或<Redirect>
组件。
All children of a <Switch> should be <Route> or <Redirect> elements. Only the first child to match the current location will be rendered.
您的<AppLayout />
组件是问题所在。 从<Switch>
中删除它并将其移动到您的身份验证页面中。
编辑
每当您在浏览器中输入新地址并按 Enter 键时,您的身份验证提供程序都会进入异步流程,这意味着每次您的应用程序中都会有一个 state 且用户未登录,那么使用此 state 的组件就会做出反应到你的改变。 同样,您应该await
setUserToken 因为在异步 function 解析之前加载设置为 false。
最后一件事在您的列表中不起作用是因为您这样编码;),如果有user
,您的公共路由会将它收到的所有呼叫重定向到/dashboard
,无论它应该是 404 路由还是现有路由。 我会建议不同的方法。 创建一个配置,在其中声明路由是否受保护,然后只有一个 AuthRoute 组件将获取路由的所有道具,并基于上下文中用户的这个新标志和 state,完成工作
const routes = [{ name: 'home', path: '/', exact: true, isProtected: false, component: Home }, { name: 'protected', path: '/dashboard', exact: true, isProtected: true, component: Dashboard }];
const AuthRoute = ({ name, path, exact, isProtected, component: Component }) => {
const { user } = useContext(userContext);
if (isProtected && !user) { // redirect to login }
if (!isProtected || (isProtected && user)) { // render route with props }
}
///...
<Switch>
{routes.map(route => <AuthRoute {...route} />
</Switch>
就在 3 到 4 天前,我遇到了同样的问题,当时一个非常善良的人非常了不起,在 discord 的 reactiflux 服务器上帮助了我。 您可能正在尝试 go 到一条受保护的路线,这会起作用,但另一条受保护的路线不起作用? 您所要做的就是在一个单独的文件中创建一个高阶组件 (HOC),您可以调用protectedRoute.js
并在此文件中:
import React, { useState, useEffect } from "react";
import { Redirect } from "react-router-dom";
export function protectedRoute(Component) {
return function ComponentCheck(props) {
const [check, setCheck] = useState(false);
const [currentUser, setCurrentUser] = useState(false);
useEffect(() => {
const user = false;
setCurrentUser(user);
setCheck(true);
}, []);
const RedirectToLogin = <Redirect to="/" />;
return check && (currentUser ? <Component {...props} /> : RedirectToLogin);
};
}
在上面的文件中,'/' 路径在我的例子中是登录页面,但是你可以说const RedirectToLogin = <Redirect to='/login' />
而不是const RedirectToLogin = <Redirect to='/' />
'/' />
然后你可以限制一个路由,例如我希望/users
路由只有在user === true
时才能访问。 因此,我可以在users.js
文件中说:
import { protectedRoute } from "./protectedRoute";
const Users = () => {
return <h2>Users</h2>;
};
export default protectedRoute(Users);
然后我还希望/dashboard
路由受到保护:
import { protectedRoute } from "./protectedRoute";
const Dashboard = () => {
return <h2>Dashboard</h2>;
};
export default protectedRoute(Dashboard);
但我不希望/home
路由受到保护,所以:
const Home = () => {
return <h2>Home</h2>;
};
export default Home;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.