React Router4小结

前言

  1. 先说明一下,我不是专门的前端,我的主业是做java的,react我也只用了几天。有错误请指出(不过我登录的时间比较少,看到了我会及时修改的)
  2. 这篇文章不会讲过多的内容,我只贴出对应需求的写法

版本

我用的应该是目前最新的版本,项目用的create-react-app构建的

  • “react”: “^16.9.0”,
  • “react-router”: “^5.0.1”,

基础用法

这段代码用于演示当我们在地址栏输入 /page1, /page2, /page1/add 时页面上出现对应不同的内容

// APP.jsx 项目根组件
import React from 'react'
import {BrowserRouter} from "react-router-dom";
import {Route, Switch} from "react-router";

export default class App {
	constructor(props){super(props)}

	render(){
		return (
			<div className="app">
				<BrowserRouter>
					<Switch>
						<Route exact path="/page1" component={组件1}/>
						<Route exact path="/page2" component={组件2}/>
						<Route exact path="/page1/add" component={add组件}/>
					</Switch>
				</BrowserRouter>
			</div>
		)
	}
}

嵌套路由和exact

  • 场景: 后台管理系统,登录页在 /login, 其他的页面在 layout里,根据菜单点击不同进入不同的路由
  • exact: 如果<Route>上加上了exact,则表示全匹配,比如以下三个路径
    • /
    • /user
    • /user/add
      对应我们有一个组件 <Home>
      当我们配置 <Route path="/" component={Home}/>,注意一下,这里没有加exact,这个意思表示/开头的任意路由都可以进入该路由,也就是 /user和/user/add也会进入该路由
      什么意思呢,就是说我们可以通过这个特性,将我们的 layout组件的路由上不加exact,在layout组件内部还有一组路由配置,这组路由配置都加上exact。我知道这么说很懵… 还是看代码吧

’以下代码示意的是后台管理系统,假设路由如下
/login 登录页
/user 用户管理页面,左侧是菜单,右侧为用户管理页面
/user/add 添加用户页面,同上,左侧是菜单
/systemSettings 系统设置页面,同上,左侧是菜单

// APP.jsx 项目根组件
import React from 'react'
import {BrowserRouter} from "react-router-dom";
import {Route, Switch} from "react-router";
// 这里后缀加jsx标注是为了说明这两个是组件,后续代码同理,不再赘述
import Login from '@/pages/Login.jsx';
import Layout from '@/components/Layout';

export default class App {
	constructor(props){super(props)}

	render(){
		return (
			<div className="app">
				<BrowserRouter>
					<Switch>
						<Route exact path="/login" component={Login}/>
						<Route path="/" component={Layout}/>
					</Switch>
				</BrowserRouter>
			</div>
		)
	}
}
// Layout组件
import React from 'react'
import {BrowserRouter} from "react-router-dom";
import {Route, Switch} from "react-router";
import User from '@/pages/User.jsx';
import UserAdd from '@/pages/UserAdd.jsx';
import SystemSettings from '@pages/SystemSettings.jsx';

export default class Layout {
	constructor(props){super(props)}

	render(){
		return (
			<div className="layout">
				假设这三个按钮是左侧菜单,点击跳转对应页面
				<button>用户管理</button>
				<button>添加用户</button>
				<button>系统设置</button>
				
				<BrowserRouter>
					<Switch>
						<Route exact path="/user" component={User}/>
						<Route exact path="/user/add" component={UserAdd}/>
						<Route exact path="/systemSettings" component={SystemSettings}/>
					</Switch>
				</BrowserRouter>
			</div>
		)
	}
}

动态路由

这个很好实现,用for循环或者map去render就好了

注意,如果想要用路径引入,就要用require函数

import React from 'react'
import {BrowserRouter} from "react-router-dom";
import {Route, Switch} from "react-router";
import User from '@/pages/User.jsx';
import UserAdd from '@/pages/UserAdd.jsx';
import SystemSettings from '@pages/SystemSettings.jsx';

// 假设这个数据来自后端
const routes = [
	{
		path: '/user',
		component: '@/pages/User.jsx'
	},
	{
		path: '/user/add',
		component: '@/pages/UserAdd.jsx'
	},
	{
		path: '/systemSettings',
		component: '@/pages/systemSettings.jsx'
	}
]


export default class Layout {
	constructor(props){super(props)}
	
	
	renderRoutes = (routes = []) => {
		return routes.map(route=>{
			// 注意这里要加 .default
			let component = require(route.component).default;
			return (
				<Route exact path={route.path} component={component}/>
			)
		});
	}
	

	render(){
		return (
			<div className="layout">
				
				<BrowserRouter>
					<Switch>
						{this.renderRoutes()}
					</Switch>
				</BrowserRouter>
			</div>
		)
	}
}


组件获取路由参数

这点是我的疏忽,我还没有用到react-redux-router,目前我讲下最简单的方法,用withRouter,比如我在<Header>组件里有个退出按钮,需要退出到登录页

import React from 'react';

class Header {
	constructor(props){super(props)}
	
	/**
	 * 退出登录
	 */ 
	logout = () => {
		this.props.history.push('/login');
	}


	render(){
		return (
			<div className="header">
				...
				<button onClick={this.logout}>退出登录</button>
			</div>
		)
	}
}

// 这里要用withRouter将组件包裹起来
export default withRouter(Header);

路由守卫

比如在上面的例子里,除了/login之外,其他所有路由都需要判断是否已经登录,登录了才能进入,或者是需要某种权限才能进入,那么这个时候就需要用到路由守卫。
我的写法可能和网上的不太一样,我也不知道可不可以,我先分享一下。

  • render属性,这是<Route>组件上的属性,使用该属性可以替代component属性,完成对组件的加载
    写一个最简单的例子
// 这两行代码是等效的
<Route exact path="/user" component={User}/>
<Route exact path="/user" render={(props) => <User {...props}/>} />

我们可以看到 render 里传入了一个箭头函数,那么既然是函数,我们就可以控制对应的返回了

<Route exact path="/user" render={(props) => {
	console.log('进入了route中的render函数');
	return (
		<User {...props}/>
	)
}} />

这个例子中,我们进入了 /user 后就会打印出 进入了route中的render函数


那么箭头函数中的props参数是什么呢?
内容包含如下

  • history: 对路由进行操作的对象,对应api百度有很多,在此不再赘述
  • location: 当前路由信息,如进入的路径
  • match: 当前路由是如何匹配进入的,如 url地址为/login匹配到了 path=/login
  • staticContext: 这个我拿到的一直是undefined,有兴趣可以去翻下官方文档,这里不说了

那么既然如此我们就可以去根据props.location里的信息去判断当前是否为登录页,如果是登录页,则直接进入,如果不是则判断本地是否有对应登录token,如果有则进入页面,否则跳转回登录
代码如下

// routerGuard.js

// 规定如果onEnter返回了pass为true,则放行,进入路由,如果返回了 redirectTo,则跳转到对应页面
const onEnter = () => { return {pass: true} }

// 设置onEnter的方法
export function setOnEnter(fn) {
	onEnter = fn;
}

// 返回一个render属性可接收的方法,这个方法需要传入一个原本的render方法
export function renderWithGuard(renderFn){
	return (props) => {
		if(onEnter){
			let filterRst = onEnter(props);
			// onEnter返回pass为true,进行渲染
			if(filterRst.pass) {
				return renderFn(props);
			} 
			// onEnter返回了 redirectTo,此处进行跳转
			else if(filterRst.redirectTo) {
				return props.history.push(filterRst.redirectTo);
			}
			// onEnter内已经处理好了,不需要我们再处理
			else if(filterRst.cancel) {
				return null;
			}
			// 未处理,进入404
			return props.history.push('/404');
		}

		// 不存在onEnter钩子,直接调用render函数
		return renderFn(props);
	}
}
// permission.js

setOnEnter((props) => {
	let { location, history } = props;
	// 当前访问路径
	let { pathname } = location;
	
	// 登录页,放行
	if(pathname === '/login'){
		return { pass:true };
	}
	
	// 假设token存在localStorage里
	let token = localStorage.getItem('token');
	// token存在,放行
	if(token){
		return { pass:true };
	}
	
	// token不存在,重定向到登录页
	let redirectTo = `/login?redirectUrl=${pathname}`;
	return { redirectTo };
})

// 渲染路由的地方,这里我们和前面的require串起来用
<Route path="/user" render={renderWithGuard((props)=> {
	let component = require('@/pages/User.jsx').default;
	return <component {...props}/>
})}

结束语

无。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值