React使用Context判断登录状态为false时重定向否则允许访问页面的实现方法
第一步:修正Context默认值
你当前的Context默认值为布尔值false,但Provider实际传递的是包含loggedIn状态和toggleLoggedIn方法的对象,直接解构会报错,先修改Context.js:
import React from 'react'; // 匹配Provider传递的结构设置默认值 export const AppContext = React.createContext({ loggedIn: false, toggleLoggedIn: () => {} });
第二步:实现认证HOC
新建withAuthProtection.js文件,代码如下:
import React, { useContext } from 'react'; import { Redirect } from 'react-router-dom'; import { AppContext } from './context'; // 高阶组件:接收需要保护的组件作为参数,返回新组件 export const withAuthProtection = (WrappedComponent) => { const ProtectedComponent = (props) => { const { loggedIn } = useContext(AppContext); // 未登录直接重定向到登录页 if (!loggedIn) { return <Redirect to="/login" />; } // 已登录则渲染原组件,透传所有props return <WrappedComponent {...props} />; }; return ProtectedComponent; };
第三步:使用HOC保护页面
有两种使用方式可选:
- 方式1:在组件导出时包裹,以
AlertsTable为例:
import { withAuthProtection } from './withAuthProtection'; function AlertsTable() { // 原有组件逻辑 } // 导出时包裹HOC,该组件只要被渲染就会触发鉴权 export default withAuthProtection(AlertsTable);
- 方式2:在路由定义时直接包裹,修改
App.js中对应路由:
// 先导入HOC和需要保护的组件 import { withAuthProtection } from './withAuthProtection'; import AlertsTable from './AlertsTable'; // 路由处直接包裹 <Route path="/open_alerts/"> <div className="alerts-table new-line-block"> <br></br> {withAuthProtection(AlertsTable)()} </div> </Route>
更适配React Router的优化方案:封装ProtectedRoute组件
相比通用HOC,专门封装路由级别的保护组件使用更便捷,不需要逐个修改组件导出:
新建ProtectedRoute.js:
import React, { useContext } from 'react'; import { Route, Redirect } from 'react-router-dom'; import { AppContext } from './context'; export const ProtectedRoute = (props) => { const { loggedIn } = useContext(AppContext); const { component: Component, ...rest } = props; return ( <Route {...rest} render={(routeProps) => { if (loggedIn) { return <Component {...routeProps} />; } return <Redirect to="/login" />; }} /> ); };
修改App.js中的路由配置,需要保护的路由直接用ProtectedRoute替换原Route即可:
// 导入ProtectedRoute import { ProtectedRoute } from './ProtectedRoute'; <Switch> <Route exact path="/login/"> <div> <LoginPage /> </div> </Route> {/* 首页需要保护 */} <ProtectedRoute exact path="/"> <div className="charts new-line-block"> <div className="split left"> <AlertsChart /> </div> <div className="split right"> <RegionCharts /> </div> </div> <br></br> <br></br> </ProtectedRoute> {/* 告警页需要保护 */} <ProtectedRoute path="/open_alerts/"> <div className="alerts-table new-line-block"> <br></br> <AlertsTable /> </div> </ProtectedRoute> {/* 其他需要保护的路由同理替换即可 */} </Switch>
补充:登录成功后跳转
可以在登录成功后跳转到首页,修改Login.js的handleSubmit逻辑:
// 导入useHistory import { useHistory } from 'react-router-dom'; export function LoginPage() { const { loggedIn, toggleLoggedIn } = useContext(AppContext); const history = useHistory(); const handleSubmit = (event) => { fetch("/accounts/login", { method: 'POST', body: JSON.stringify({ 'username': user, 'password': password }) }) .then((response) => { if(response.ok) { toggleLoggedIn(true); // 登录成功跳转到首页 history.push('/'); } else { // 错误处理逻辑 } }) } // 原有组件逻辑 }
内容的提问来源于stack exchange,提问作者xdgdeveloper
相关产品推荐
相关产品推荐

