react-router6 实现私密路由保护功能+重定向之前页面
- 配置路由
- 实现一个Context管理需要的状态组件,包裹路由
- 组件
- 可以把value里面的值都封装到一个hook里面,方便拿取
- 包裹后的App组件
- 私密路由保护:没登陆,没token值,B组件就进不去
- 包裹B组件,实现如下功能
- 重定向之前页面
简介:在vue中,实现路由保护有router.beforeEach
的全局路由守卫,afterEach
后置路由首位和beforeEnter
独享路由守卫,那么在react中该怎么实现?
基于react的灵活性,实现以上方式的方法基本我分为3种,组件校验,函数校验,或者两者结合。对于利用js函数形式校验并管理路由可以看这篇文章,详细介绍了usRoutes()
统一管理路由和校验的方式。这里只大致介绍组件形式。
思路:首先实现私密路由保护,react中除了函数形式外,组件形式是使用一个私密路由组件来包裹需要保护的组件,这时候就需要用到token,或者别的什么请求值。所以首先让这些值得能够在全局中传递,然后在私密组件中进行判断校验。 至于重定向之前页面或者跳转其他页面就只需要用到react-router6的hook和组件就ok
配置路由
注:此处只是简单的demo,真实项目里面路由是统一管理,用useRoutes
这个hooks拿取,搭配<Outlet/>
或者直接map遍历的形式,像以下的用在少部分处
const App = () => {
/......./
return (
<>
<h1>React Router</h1>
<Routes>
<Route index element={<A />} />
<Route path="/home" element={<A />} />
<Route path="/bpath" element={<B />} />
<Route path="*" element={<Error />} />
</Routes>
</>
);
};
实现一个Context管理需要的状态组件,包裹路由
组件
// AuthProvider.jsx
//context
export const demoTwoContext = React.createContext()
//组件封装
const AuthProvider = (props) => {
const [token, setToken] = useState(null);
const handleLogin = useCallback(async() => {
const token = await 请求数据(用到redux或者mobx);
setToken(token);
}, []);
const handleLogout = useCallback(() => {
setToken(null);
}, []);
//添加其他方法或者状态
const value = {
token,
onLogin: handleLogin,
onLogout: handleLogout,
};
return <demoTwoContext.Provider value={value}>
{props.children}
</demoTwoContext.Provider>;
};
export default AuthProvider;
可以把value里面的值都封装到一个hook里面,方便拿取
//useAuth.js
import React from "react";
import { demoTwoContext } from "./AuthProvider ";
export const useAuth = () => {
return React.useContext(demoTwoContext);
};
包裹后的App组件
const App = () => {
/......./
return (
- <>
+ <AuthProvider>
<h1>React Router</h1>
<Routes>
<Route index element={<A />} />
<Route path="/home" element={<A />} />
<Route path="/bpath" element={<B />} />
<Route path="*" element={<Error />} />
</Routes>
- </>
+ </AuthProvider>
);
};
私密路由保护:没登陆,没token值,B组件就进不去
即使知道B组件的路由地址,想直接输入url进入,这个方式也可以阻止。
因为要用它包裹其他组件,所以返回一个children
PrivateRoute.jsx
import React from "react";
import { Navigate } from "react-router-dom";//react router6的跳转组件
import { useAuth } from "./hooks/useAuth";
/**
*组件将检查身份验证令牌是否存在。
*如果存在,则该组件将呈现其子级。
*如果它不存在,用户将获得一个条件重定向
*/
const ProtectedRoute = (props) => {
const { token } = useAuth(); //刚才封装的hook,这样就不用一直useContext拿值了
if (!token) {
return <Navigate to="/home" replace />;
}
return props.children
};
export default ProtectedRoute;
包裹B组件,实现如下功能
此时实现功能:进去B组件时候没有登陆,无token值,就进不去,会重定向/home页面,同时知道B组件url地址,直接输入也会被拦截
<Routes>
<Route index element={<A />} />
<Route path="/home" element={<A />} />
<Route
path="/dashboard"
element={//现在,当用户单击按钮注销时,他们将通过新的受保护路由获得隐式重定向,因为令牌不再存在。此外,如果用户未通过身份验证,则此用户无法访问受保护的路由
<ProtectedRoute>
<B />
</ProtectedRoute>
}
/>
<Route path="*" element={<Error />} />
</Routes>
重定向之前页面
登录后,您将被重定向到以前访问过的页面。换句话说:如果您在受保护的路由上打开应用程序,但您没有登录,则会重定向到“登录”页面。登录后,您将获得重定向到所需的受保护路由。
const ProtectedRoute = (props) => {
const { token } = useAuth();
const location = useLocation();
if (!token) { //重定向之前页面
return <Navigate to="/home" replace state={{ from: location }} />;
}
return props.children
};
export default ProtectedRoute;
接下来,我们可以再次从 React Router 的位置获取上一页的状态。当登录发生时,我们可以使用上一页将用户重定向到此所需页面。如果此页面从未设置为状态,则默认为“B”页面:
const AuthProvider = ({ children }) => {
const [token, setToken] = useState(null);
const navigate = useNavigate() // 跳转
const location = useLocation() //获取上一页的状态
const handleLogin = usecallback(async () => {
const token = await 请求数据(用到redux或者mobx);
setToken(token);
const origin = location.state?.from?.pathname || '/b';
navigate(origin);
},[location.state?.from?.pathname, navigate])
...
};
over