如何使用react-router-dom创建一个受保护的路由,并将响应存储在localStorage中,以便用户下次打开时可以再次查看其详细信息。登录后,应重定向到仪表板页面。
所有功能都添加在ContextApi中。
Codesandbox链接:Code
我尝试过,但无法实现。
路由页面
import React, { useContext } from "react";
import { globalC } from "./context";
import { Route, Switch, BrowserRouter } from "react-router-dom";
import About from "./About";
import Dashboard from "./Dashboard";
import Login from "./Login";
import PageNotFound from "./PageNotFound";
function Routes() {
const { authLogin } = useContext(globalC);
console.log("authLogin", authLogin);
return (
<BrowserRouter>
<Switch>
{authLogin ? (
<>
<Route path="/dashboard" component={Dashboard} exact />
<Route exact path="/About" component={About} />
</>
) : (
<Route path="/" component={Login} exact />
)}
<Route component={PageNotFound} />
</Switch>
</BrowserRouter>
);
}
export default Routes;
上下文页面
import React, { Component, createContext } from "react";
import axios from "axios";
export const globalC = createContext();
export class Gprov extends Component {
state = {
authLogin: null,
authLoginerror: null
};
componentDidMount() {
var localData = JSON.parse(localStorage.getItem("loginDetail"));
if (localData) {
this.setState({
authLogin: localData
});
}
}
loginData = async () => {
let payload = {
token: "ctz43XoULrgv_0p1pvq7tA",
data: {
name: "nameFirst",
email: "internetEmail",
phone: "phoneHome",
_repeat: 300
}
};
await axios
.post(`https://app.fakejson.com/q`, payload)
.then((res) => {
if (res.status === 200) {
this.setState({
authLogin: res.data
});
localStorage.setItem("loginDetail", JSON.stringify(res.data));
}
})
.catch((err) =>
this.setState({
authLoginerror: err
})
);
};
render() {
// console.log(localStorage.getItem("loginDetail"));
return (
<globalC.Provider
value={{
...this.state,
loginData: this.loginData
}}
>
{this.props.children}
</globalC.Provider>
);
}
} Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
对于v6:
import { Routes, Route, Navigate } from "react-router-dom"; function App() { return ( <Routes> <Route path="/public" element={<PublicPage />} /> <Route path="/protected" element={ <RequireAuth redirectTo="/login"> <ProtectedPage /> </RequireAuth> } /> </Routes> ); } function RequireAuth({ children, redirectTo }) { let isAuthenticated = getAuth(); return isAuthenticated ? children : <Navigate to={redirectTo} />; }链接到文档: https://gist.github.com/mjackson/d54b40a094277b7afdd6b81f51a0393f
问题
<BrowserRouter> <Switch> {authLogin ? ( <> <Route path="/dashboard" component={Dashboard} exact /> <Route exact path="/About" component={About} /> </> ) : ( <Route path="/" component={Login} exact /> )} <Route component={PageNotFound} /> </Switch> </BrowserRouter>Switch不处理除Route和Redirect组件之外的任何渲染。如果你想要像这样“嵌套”,那么你需要将每个组件包装在通用的路由中,但这完全是不必要的。你的登录组件也没有处理重定向回原来访问的“主页”或私有路由。
解决方案
react-router-domv6在版本6中,自定义路由组件已经不再流行,推荐的方法是使用身份验证布局组件。
import { Navigate, Outlet } from 'react-router-dom'; const PrivateRoutes = () => { const location = useLocation(); const { authLogin } = useContext(globalC); if (authLogin === undefined) { return null; // or loading indicator/spinner/etc } return authLogin ? <Outlet /> : <Navigate to="/login" replace state={{ from: location }} />; }...
<BrowserRouter> <Routes> <Route path="/" element={<PrivateRoutes />} > <Route path="dashboard" element={<Dashboard />} /> <Route path="about" element={<About />} /> </Route> <Route path="/login" element={<Login />} /> <Route path="*" element={<PageNotFound />} /> </Routes> </BrowserRouter>或者
const routes = [ { path: "/", element: <PrivateRoutes />, children: [ { path: "dashboard", element: <Dashboard />, }, { path: "about", element: <About /> }, ], }, { path: "/login", element: <Login />, }, { path: "*", element: <PageNotFound /> }, ];...
export default function Login() { const location = useLocation(); const navigate = useNavigate(); const { authLogin, loginData } = useContext(globalC); useEffect(() => { if (authLogin) { const { from } = location.state || { from: { pathname: "/" } }; navigate(from, { replace: true }); } }, [authLogin, location, navigate]); return ( <div style={{ height: "100vh" }} className="d-flex justify-content-center align-items-center" > <button type="button" onClick={loginData} className="btn btn-primary"> Login </button> </div> ); }react-router-domv5创建一个消费您的身份验证上下文的
PrivateRoute组件。const PrivateRoute = (props) => { const location = useLocation(); const { authLogin } = useContext(globalC); if (authLogin === undefined) { return null; // or loading indicator/spinner/etc } return authLogin ? ( <Route {...props} /> ) : ( <Redirect to={{ pathname: "/login", state: { from: location } }} /> ); };更新您的
Login组件以处理重定向回原来访问的路由。export default function Login() { const location = useLocation(); const history = useHistory(); const { authLogin, loginData } = useContext(globalC); useEffect(() => { if (authLogin) { const { from } = location.state || { from: { pathname: "/" } }; history.replace(from); } }, [authLogin, history, location]); return ( <div style={{ height: "100vh" }} className="d-flex justify-content-center align-items-center" > <button type="button" onClick={loginData} className="btn btn-primary"> Login </button> </div> ); }在“平面列表”中渲染所有路由
function Routes() { return ( <BrowserRouter> <Switch> <PrivateRoute path="/dashboard" component={Dashboard} /> <PrivateRoute path="/About" component={About} /> <Route path="/login" component={Login} /> <Route component={PageNotFound} /> </Switch> </BrowserRouter> ); }