Fork me on GitHub

react-router 4.x笔记

文章概述

本篇文章记录react-router 4.x的笔记。

参考资料

简介

  • React Router是React官方推荐的标准路由库,用来管理一个多视图的React应用中那些来回切换的页面URL。
  • React Router V4基于Lerna管理多个Repository。此代码库包括:
包名 描述
react-router React Router 核心组件
react-router-dom 用于 DOM 绑定的 React Router
react-router-native 用于React Native的 React Router
react-router-redux React Router 和 Redux 的集成
react-router-config 静态路由配置帮助助手
  • React Router V4遵循了Reac的理念:万物皆组件。因此 Route、Link、Switch等都是一个普通的组件。
1
组件里也可以添加router,路由放在组件中,需要的时候再去定义;
  • React Router V4的特点是:声明式、可组合。

插件安装

react-router-dom

react-router-dom提供了BrowserRouter,Route,Link等api,我们可以通过dom的事件控制路由,对比react-router多出了 DOM类组件。如果搭配redux,你还需要使用react-router-redux。

安装
1
$ npm install react-router-dom -S
引入

在react应用中,引入相关路由组件即可使用:

1
import {HashRouter as Router, Link, Route, Switch} from 'react-router-dom';

内置组件简介

常用的组件有:

  • Router:路由;
  • Route:路由规则;
  • Switch:包裹Route,避免多次匹配;
  • Link:与Route平级,相当于a标签,用来设置与Route的路径对应的地址,导航作用;
  • NavLink:同Link,新增了一些状态控制api;
  • Redirect: url重定向;

Router

在 React Router 4中,你可以将各种组件及标签放进 组件中,他的角色也更像是Redux中的 。不同的是是用来保持与store的更新,而是用来保持与location的同步。示例如下:

使用示例
1
2
3
4
5
6
7
8
9
10
11
12
<Router>
<div>
<ul>
<li><Link to="/">首页</Link></li>
<li><Link to="/about">关于</Link></li>
<li><Link to="/topics">主题列表</Link></li>
</ul>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/topics" component={Topics}/>
</div>
</Router>
概述
  • Router组件下只允许存在一个子元素;
  • Router是所有路由组件共用的底层接口,一般我们的应用并不会使用这个接口,而是使用高级的路由:
1
2
3
4
<BrowserRouter>:使用HTML5提供的history API(pushState,replaceState和popstate事件)来保持UI和URL的同步;
<HashRouter>:使用URL的hash (例如:window.location.hash) 来保持UI和URL的同步,兼容老的浏览器,最终的url中会有明显的#(http://example.com/#/about);
<MemoryRouter>:能在内存保存你 “URL” 的历史纪录(并没有对地址栏读写);
<StaticRouter>:从不会改变地址;

注意:BrowserRouter


如果使用BrowserRouter,path配置时,最好不要使用双斜线,webpack服务二次刷新页面会报错‘cannot get …’,需要配置devServer添加如下配置:

1
2
3
4
5
6
7
8
devServer: {
//...
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebookincubator/create-react-app/issues/387.
disableDotRule: true,
},
}

Route

概述

Route控制了路径对应显示的组件或要渲染的内容,path属性与Link的to属性进行匹配。

属性
path

path(string):路由的匹配路径;

1
2
//【示例】
<Route path="/users/:id" component={User}/>

path通配符传参:

【常用通配符】(为了区分,中括号内的是通配符)

1
2
3
4
5
6
7
> [:paramName]:参数通配符;
1> paramName匹配URL的一个部分,直到遇到下一个/、?、#为止;
2> 这个路径参数在组件中,可以通过this.props.params.paramName取出;
3> 目标组件页面可以通过render返回的函数中添加route(props)参数来获取参数值:{route.match.params.id}。
> [()]:()表示URL的这个部分是可选的。
> [*]:*匹配任意字符,直到模式里面的下一个字符为止。匹配方式是非贪婪模式。
> [**]:** 匹配任意字符,直到下一个/、?、#为止。匹配方式是贪婪模式。

【通配符示例】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//【传参通配符】
<Route path="/hello/:name">
// 匹配 /hello/michael
// 匹配 /hello/ryan

//【其他通配符】
<Route path="/hello(/:name)">
// 匹配 /hello
// 匹配 /hello/michael
// 匹配 /hello/ryan

<Route path="/files/*.*">
// 匹配 /files/hello.jpg
// 匹配 /files/hello.html

<Route path="/files/*">
// 匹配 /files/
// 匹配 /files/a
// 匹配 /files/a/b

<Route path="/**/*.jpg">
// 匹配 /files/hello.jpg
// 匹配 /files/path/to/file.jpg
exact

exact(bool): 为true时,要求路径与location.pathname(即path)必须完全匹配;

测试路径 path exact 是否匹配
/one /one/two true
/one /one/two false
1
2
//【示例】
<Route exact path="/one" component={About}/>
strict

strict(bool): true的时候,匹配url时,结尾斜线也要匹配;

测试路径 path strict 是否匹配
/one/ /one true
/one/ /one/ true
/one/ /one/two true
1
2
//【示例】
<Route strict path="/one/" component={About}/>
component

component:表示path对应显示的组件;

1
2
【注意】
<Route component>的优先级要比<Route render>高,所以不要在同一个<Route>中同时使用这两个属性。
1
2
3
4
5
6
7
//【示例】
//路由:
<Route path="/user/:username" component={User}/>
//渲染的组件:利用match获取参数;
const User = ({ match }) => {
return <h1>Hello {match.params.username}!</h1>
}
render

render(func):以函数方式返回渲染的内容,可替代要显示的component;

1
2
//【示例】
<Route path="/home" render={() => <div>Home</div>}/>
children

children(func): 与render属性的工作方式基本一样,不管地址匹配与否都会被调用;

用于控制路由跳转的;

API属性
  • to(string|object):要跳转的路径或地址;
  • replace(bool):为true时,点击链接后将使用新地址替换掉访问历史记录里面的原地址;为false时,点击链接后将在原有访问历史记录的基础上添加一个新的纪录。默认为false;
示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { Link } from 'react-router-dom'

//to: string
<Link to="/a/123">xxx</Link>
<Link to="/about">关于</Link>

//to: object
<Link to={{
pathname: '/courses',
search: '?sort=name',
hash: '#the-hash',
state: { fromDashboard: true }
}}/>

//replace
<Link to="/courses" replace />

的一个特定版本, 会在匹配上当前 URL 的时候会给已经渲染的元素添加样式参数;

API属性
1
2
3
4
5
> activeClassName(string):设置选中样式,默认值为 active;
> activeStyle(object):当元素被选中时, 为此元素添加样式;
> exact(bool):为true 时, 只有当地址完全匹配 class 和 style 才会应用;
> strict(bool):为true 时,在确定位置是否与当前 URL 匹配时,将考虑位置 pathname 后的斜线;
> isActive(func):判断链接是否激活的额外逻辑的功能;
activeClassName

activeClassName(string):设置选中样式类选择器,默认值为active;

1
2
3
4
<NavLink
to="/xxx"
activeClassName="selected"
>显示xxx</NavLink>
activeStyle

activeStyle(object):当元素被选中时, 为此元素直接添加样式;

1
2
3
4
5
6
7
<NavLink
to="/faq"
activeStyle={{
fontWeight: 'bold',
color: 'red'
}}
>FAQs</NavLink>
exact

exact(bool):为true 时, 只有当地址完全匹配 class 和 style 才会应用;

1
2
3
4
<NavLink
exact
to="/profile"
>Profile</NavLink>
strict

strict(bool):为true 时,在确定位置是否与当前 URL 匹配时,将考虑位置 pathname 后的斜线;

1
2
3
4
<NavLink
strict
to="/events/"
>Events</NavLink>
isActive

isActive(func):判断链接是否激活的额外逻辑的功能;

1
2
3
4
5
6
7
8
9
10
11
12
13
// 当event id为奇数的时候,激活链接
const oddEvent = (match, location) => {
if (!match) {
return false
}
const eventID = parseInt(match.params.eventID)
return !isNaN(eventID) && eventID % 2 === 1
}

<NavLink
to="/events/123"
isActive={oddEvent}
>Event 123</NavLink>

Switch

Switch常常会用来包裹多个Route,根据path匹配一个Route,它里面不能放其他元素,仅用来匹配显示一个路由,避免路由的重复匹配问题。

Redirect

渲染将导航到新位置。新位置将覆盖历史堆栈中的当前位置,如服务器端重定向(HTTP 3xx)。

属性
to

to(string|object): 要重定向到的网址或位置;

1
2
3
4
5
6
<Redirect to="/somewhere/else"/>
<Redirect to={{
pathname: '/login',
search: '?utm=your+face',
state: { referrer: currentLocation }
}}/>
push

push(bool):当为true时,重定向会将新条目推入历史记录,而不是替换当前条目。

1
<Redirect push to="/somewhere/else"/>
from

from(string):匹配需要要重定向的路径名。这只能用于在内部呈现时匹配位置。

1
2
3
4
<Switch>
<Redirect from='/old-path' to='/new-path'/>
<Route path='/new-path' component={Place}/>
</Switch>
示例代码

根据登录或未登录渲染不同改的内容:

1
2
3
4
5
import { Route, Redirect } from 'react-router'

<Route exact path="/" render={() => (
loggedIn ? (<Redirect to="/dashboard"/>) : (<PublicHomePage/>)
)}/>

Route内置对象

react router提供了几个重要的内置对象,用来获取页面路由的信息,如下:

  • location;
  • history;
  • match;

match

match(这里称匹配对象)包含与Route的path匹配的信息;

获取方式
component

Route component中使用this.props.match获取match, 或者使用箭头函数传入一个match:

1
2
3
4
5
<Route path="/user/:username" component={User}/>

const User = ({ match }) => {
return <h1>Hello {match.params.username}!</h1>
}

render

Route render中使用({ match }) => ()方式获取:

1
2
3
4
5
<Route path={`${this.props.match.path}/:id`}
render={({match}) => {
return (<div>当前组件是带参数的A,参数是:{match.params.id}</div>);
}
}/>
children

Route children中用({ match }) => ()方式获取:

1
<Route children={({ match, ...rest }) => (//...)}/>
属性

match对象包含以下属性:

  • params(object):根据path路径(url)解析相关参数信息;
  • isExact(bool): 如果匹配整个URL,则为true(不包括尾部斜杠字符);
  • path(string):用于匹配的路径模式。 用于构建嵌套的Route;
  • url(string): URL的匹配部分。 用于构建嵌套的Link;

location

页面的位置信息;

简介

location代表应用程序现在的位置,您希望它去的位置,甚至是它的位置。 它看起来像这样:

1
2
3
4
5
6
7
8
9
{
key: 'ac3df4', // not with HashHistory!
pathname: '/somewhere'
search: '?some=search-string',
hash: '#howdy',
state: {
[userDefined]: true
}
}
获取方式

与match类似

history

浏览器的路由历史,获取方式同match类似;

属性方法

history对象通常具有以下属性和方法:

  • length - (number) 历史堆栈中的条目数;
  • action - (string) 当前操作(PUSH,REPLACE或POP);
  • location - (object) 目前的location对象。
  • push(path, [state]) - (function) 将新条目推送到历史堆栈。
  • replace(path, [state]) - (function) 替换历史堆栈上的当前条目。
  • go(n) - (function) 通过n个条目移动历史堆栈中的指针;
  • goBack() - (function) 回退一条历史;
  • goForward() - (function) 前进一条历史;
  • block(prompt) - (function) 组织导航;

案例

简单传参

路由显示带参数组件A和不带参数组件B:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import {HashRouter as Router, Link, Route, Switch} from 'react-router-dom';
class A extends React.Component {
render() {
return (
<div>
Component A
接受的参数是:{this.props.match.params.id}
</div>
);
}
}

class B extends React.Component {
render() {
return (
<div>Component B</div>
);
}
}

//Link用作跳转导航
class Wrapper extends React.Component {
render() {
return (
<div>
<Link to="/a/123">显示组件A,带参数</Link>
<br/>
<Link to="/b">显示组件B</Link>
{this.props.children}
</div>
);
}
}

//定义router路由规则,用于匹配Link做跳转导航;
ReactDOM.render(
<Router>
<Wrapper>
{/*带参数*/}
<Route path="/a/:id" component={A}/>
<Route path="/b" component={B}/>
</Wrapper>
</Router>,
document.getElementById('app')
);
相同路径匹配真假参数
  • 子组件中使用Route来匹配带参数和不带参数path,使用Switch来进行匹配;
  • 路径结构相同时:区分子路径是否是参数的办法是,将参数通配路径置后;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import {HashRouter as Router, Link, Route, Switch} from 'react-router-dom';
class A extends React.Component {
render() {
return (
<div>
Component A
{/*子组件内部switch匹配对应路由规则*/}
<Switch>
{/*path不是完全匹配,如果需要完全等于某路径,需要path前面加上exact关键字*/}
<Route exact path={`${this.props.match.path}`}
render={() => {
return (<div>当前组件是不带参数的A</div>);
}}/>
{/*路径结构相似,为了区分子路径名和通配参数,需要将带通配的参数Route放在后面;*/}
<Route exact path={`${this.props.match.path}/sub`}
render={() => {
return (<div>当前组件是与带参数的A路径结构相同,但是sub不是参数</div>);
}}/>
<Route path={`${this.props.match.path}/:id`}
render={(route) => {
return (<div>当前组件是带参数的A,参数是:{route.match.params.id}</div>);
}}/>
</Switch>
</div>
);
}
}

class B extends React.Component {
render() {
return (
<div>Component B</div>
);
}
}

//Link用作跳转导航
class Wrapper extends React.Component {
render() {
return (
<div>
<Link to="/a/sub">显示组件A的sub路径,不带参数</Link>
<br/>
<Link to="/a/123">显示组件A,带参数</Link>
<br/>
<Link to="/a">显示组件A,不带参数</Link>
<br/>
<Link to="/b">显示组件B</Link>
{this.props.children}
</div>
);
}
}

//定义router路由规则,用于匹配Link做跳转导航;
ReactDOM.render(
<Router>
<Wrapper>
{/*带参数*/}
<Route path="/a" component={A}/>
<Route path="/b" component={B}/>
</Wrapper>
</Router>,
document.getElementById('app')
);
坚持原创技术分享,您的支持将鼓励我继续创作!