React Router 是完整的 React 路由解决方案。
React Router 保持 UI 与 URL 同步。它拥有简单的 API 与强大的功能例如代码缓冲加载、动态路由匹配、以及建立正确的位置过渡处理。你第一个念头想到的应该是 URL,而不是事后再想起。
使用一下命令安装 React
的路由。
react-router
: 实现了路由的核心功能
react-router-dom
: 基于 react-router
,加入了在浏览器运行环境下的一些功能,例如:Link
组件,会渲染一个 a
标签,Link
组件源码 a
标签行; BrowserRouter
和 HashRouter
组件,前者使用pushState
和 popState
事件构建路由,后者使用window.location.hash
和 hashchange
事件构建路由。
// react-router-dom 依赖于 react-router,安装它时会自动安装 react-router
npm i react-router-dom --save
react-router
和 vue-router
基本原理比较相似,都是通过控制网页 url
变化实现前端路由,在不刷新页面的基础上更新页面的内容,或者跳转页面。
React-router
配置和调用的简单示例// App.js
import React from 'react';
// 从 react-router-dom 中导入配置路由需要的组件
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
// 导入被路由的子组件
import About from './components/About'
import Topics from './components/Topics'
import './App.css';
// 配置路由并调用路由
function App() {
return (
<div className="App">
<div>其他内容区域</div>
<Router>
<div>
<ul>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
<hr />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
</div>
</Router>
</div>
);
}
export default App;
注: 如果一个组件中需要配置或使用路由,建议将 BrowserRouter
作为其根组件。
在项目研发过程中,一般一个项目的根组件就是根路由,其上所有的路由都是在根路由的基础上衍生的子路由,由于react-router
本身的特点比较特殊,我们会将
组件渲染在根路由配置中,然后将 index.js
逻辑入口中的根组件渲染成根路由组件,以下是示例:
// 根路由配置文件 router.js
import React, { Component } from 'react';
import { BrowserRouter as Router} from 'react-router-dom';
import App from './App';
class Router extends Component {
render() {
return (
<Router>
<App />
</Router>
);
}
}
export default Router;
// 逻辑入口 index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Router from './router';
// 用 Router 组件代替 App 作为根组件
ReactDOM.render(<Router />, document.getElementById('root'));
嵌套路由是在当前被路由组件内部再配置路由并且在对应位置渲染即可。
比如在上面的示例中,
组件中有两个被路由组件,分别是
和
,这相当于一级路由,如果
组件中还有子路由
组件和
组件,那么可以进行如下配置:
// About.js
import React from 'react'
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import A1 from './A-1'
import A2 from './A-2'
class About extends React.Component {
render() {
return (
<Router>
<ul>
<li>
<Link to="/about/a1">a-module1</Link>
</li>
<li>
<Link to="/about/a2">a-module1</Link>
</li>
</ul>
<Route path="/about/a1" component={A1} />
<Route path="/about/a2" component={A2} />
</Router>
);
}
}
export default About;
在上面的示例中,如果在菜单切换到
组件时,需要展示
组件,就要设置默认路由:
react-router
可以通过两种方式实现路由:
方式一
{/* 当路由切换到 /about 时,会自动渲染 A1 组件 */}
方式二
{/* 当路由切换到 /about 时,会自动重定向到 /about/a1 */}
组件会重定向 url
。
react-router
4.x 版本推出之后,路由配置不再有集中的配置。
路由传参时单页面应用开发常见的需求。
url
中使用通配符直接传参给一个需求,有一个博客列表菜单,点任意一篇,要在路由位置渲染对应的数据。
那么我们就需要在点击菜单时渲染路由组件并传参:
// Blog-list.js
import React from 'react'
import { BrowserRouter as Router, Route, Link, Redirect } from "react-router-dom";
import Blog from './Blog'
class BlogList extends React.Component {
render() {
return (
<Router>
<ul>
<li>
<Link to="/blog/1">博客1</Link>
</li>
<li>
<Link to="/blog/2">博客2</Link>
</li>
<li>
<Link to="/blog/3">博客3</Link>
</li>
</ul>
<Route path="/blog/:id" component={Blog} />
</Router>
);
}
}
export default BlogList
在
组件中获取参数
// Blog.js
import React from 'react'
class A1 extends React.Component {
render() {
// 接受参数列表
const match = this.props.match;
return <h1>
{match.params.id}
</h1>;
}
}
export default A1
这种调用和传参会在 url
中暴露参数。
query
传参详情页
接收参数
import React from 'react'
class Detail extends React.Component {
render() {
// 接受 query 的参数
const query = this.props.location.query;
console.log(query);
return <h1>详情页</h1>;
}
}
export default Detail;
注:
query
传参不会将参数暴露在 url
中,但是在刷新当前页面时,参数会丢失。query
传参是不需要配置路由表的。state
传值详情页
接收参数
import React from 'react'
class Detail extends React.Component {
render() {
// 接受 state 的参数
const state = this.props.location.state;
console.log(state);
return <h1>详情页</h1>;
}
}
export default Detail;
注:
query
一样 state
传参时,参数也是加密的。react-router
为 state
传值提供了各种动态操作的方式。search
传参详情页
react-router
提供
组件用来根据条件,选择性渲染列表中的一个路由。
给一个需求,用户如果对 url
做一些违规操作,比如输入一个不存在的路由时,展示 404 组件,那么代码可能是这样
{/* 404 组件 */}
这种写法,当路由匹配到 '/about'
和 'user'
时,
组件和
会和 404 组件同时渲染。
但实际需求它们是互斥的,这个时候就要用到
组件。
渲染第一个被location匹配到的并且作为子元素的
或者
{/* Switch 和 Link、Route 一样,在使用时需要先从 react-router-dom 中引入 */}
{/* 404 组件 */}
和
如果一个页面有这样的基本操作,当前端访问 '/'
时,渲染
组件,当访问 '/about'
时,渲染
组件。
先看路径区别:
BorserRouter:
http://www.xxx.com/about
HashRouter:
http://www.xxx.com/#/about
如果使用
,每次前端做出请求,服务器都要对请求做出分析,并且返回该请求对应的内容给前端,前端渲染即可。
如果使用
,'#'
后面的内容不会传到服务器,无论路由如何,对于服务器端来说,访问的都是 '/'
,每次请求,服务器都返回同样的内容给浏览器,由浏览器自己解析 '#'
之后的内容,渲染对应的内容。
react-router
之所以推出 v4 版本,就是因为觉得静态路由还有很多不完善的地方。
react-router
v4 允许使用各种条件判断是否需要渲染某个
组件。
比如某个组件需要用户满足权限才能渲染:
{
userState == 4 &&
,
}