react hooks 已经盛行一段时间。最新的react-router-dom 和react-redux也都同时支持了hooks写法。我们可以抛弃 withRouter轻松获取location等对象,也再也无须写mapStateToProps和mapDispatchToProps。下面我们结合react-router-dom实现一个简单的登录验证和全局拦截实例。
注意:react版本至少要16.8,
本实例基础库版本如下:
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.0",
先捋一下我们要实现的基本效果:
1 根路由是login页面。如果没有登录,同时该页面设置了某个属性,我们暂且把它设置为auth,也就是该页面需要被拦截。那么我们需要把它重定向到登录页面,
如果它不要被拦截。则直接定位404。
2如果已经登录,我们在每次页面路径切换的时候,需要看当前的页面路径是否是login,如果是login,则我们需要把它重定向到首页,比如home。一般登录以后我们是不允许再回到登录页。而如果当前的页面地址不存在,我们则要果断定位到404。
基本逻辑清晰了以后,我们开始写基本逻辑和配置
项目结构:
App.js
router
----authRoute.js
-----routes.js
-------------------------------------app.js-----------------------------------------------------------
import { BrowserRouter as Router, Switch, Route } from "react-router-dom"
import routes from "./router/routes"
import AuthRoute from "./router/authRoute"
function App() {
return (
{
routes.map((item, index) => {
return (
)
})
}
);
}
import React from 'react'
import Home from "../pages/Home"
import Login from "../pages/Login"
import About from "../pages/About"
import NotFound from "../pages/NotFound"
-------------------------------------------routes.js----------------------------------------------------------
const routes = [
{ name: "", path: "/", component:Login,exact:true},
{ name: "login", path: "/login", component:Login,exact:false},
{ name: "home", path: "/home", component:Home,auth:true,exact:false},
{ name: "about", path: "/about", component: About,auth:true, exact: false },
{ name: "404", path: "/404", component: NotFound, exact: false },
]
export default routes;
-------------------------------------------authRoute.js----------------------------------------------------------
import React from 'react'
import { Redirect, Route } from "react-router-dom"
const AuthRoute = (props) => {
let { location, routeData } = props
let { pathname } = location
const isLogin = localStorage.getItem("isLogin")
//当前路径所在的路由item信息
const targetRouteObj = routeData.find((item) => item.path == pathname)
//未登录,路径存在,且不需要拦截则直接进入该页面
if (targetRouteObj && !targetRouteObj.auth && !isLogin) {
let { component } = targetRouteObj
return
}
//登录
if (isLogin) {
// 如果要进入登录页面
if (pathname == "/login") {
return
} else {
//页面地址存在
if (targetRouteObj) {
return
} else {
//页面地址不存在
return
}
}
} else {
if (targetRouteObj && targetRouteObj.auth) {
return
} else {
return
}
}
}
export default AuthRoute
----------------------------------------login.js------------------------------------------------------------
import React, { useState } from 'react'
import { useHistory} from "react-router-dom"
import "./login.css"
function Login() {
const [user,setUser]=useState("")
const [password, setPassword] = useState("")
let history=useHistory()
const getVal = (obj) => {
let type = obj.target.dataset.type
if (type == "user") {
setUser(obj.target.value)
} else {
setPassword(obj.target.value)
}
}
const login = (props) => {
localStorage.setItem("isLogin", true)
history.push("/home")
}
return (
用户名是:{ user}
密码是:{ password}
)
}
export default Login
接下来我们解释一下基本逻辑
routes.js是我们路由配置的数组,这里我们给需要拦截的页面添加了一个auth熟悉。auth:true,表示该页面需要拦截验证,否则不需要。我们把login和404除掉了这个配置,authRoute是我们封装的一个Route组件。我们最后需要导出一个Route组件,最后挂到app.js的switch中,
每次页面切换的时候,我们都获取到当前path所对应的一条json信息。根据我们之前的逻辑。如果未登录。我们需要判断当前页面是否设置了拦截处理标志,如果登录了,我们需要判断下当前的页面路径是否是千万登录页。亦是否是一个根本不存在的页面。我们做相应的逻辑处理。最后在app.js中。我们不再用Route,而采用封装了逻辑的AuthRoute 。这样就可以实现全局路由拦截。
本实例中我们采用了react-router-dom 的hooks。useHistory()获取到路由实例对象。直接通过它的replace和push实现重定向