如何使用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> ); } }
P粉1229324662023-09-22 12:07:30
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
P粉5877801032023-09-22 00:11:42
<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-dom
v6在版本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-dom
v5建立一個消費您的身分驗證上下文的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> ); }