react 2 - route

route可以说是现在的单页应用必备的功能了, 那么在react里, 官方也提供了一个路由库react-router, 也是唯一的一个路由库, 也提供了官方教程, 下面来看看如何使用吧.

注: 本文基于react-router 4.x

先看一个简单的例子, 从这个例子来学习router的基本使用方法.

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
66
67
68
69
70
71
72
73
74
75
76
77
78
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route, HashRouter, Link, NavLink } from 'react-router-dom';

var destination = document.querySelector('#container');

class App extends Component {
render() {
return (
<div>
<h1>Simple SPA</h1>
<ul className='header'>
<li>
<NavLink exact to='/' activeClassName='active'>
Home
</NavLink>
</li>
<li>
<NavLink to='/stuff' activeClassName='active'>
Stuff
</NavLink>
</li>
<li>
<NavLink to='/contact' activeClassName='active'>
Contact
</NavLink>
</li>
</ul>
<div className='content'>{this.props.children}</div>
</div>
);
}
}

var Home = () => (
<div>
<h2>HELLO</h2>
<p>
Cras facilisis urna ornare ex volutpat, et convallis erat elementum. Ut aliquam, ipsum vitae gravida suscipit, metus dui bibendum est, eget
rhoncus nibh metus nec massa. Maecenas hendrerit laoreet augue nec molestie. Cum sociis natoque penatibus et magnis dis parturient montes,
nascetur ridiculus mus.
</p>
<p>Duis a turpis sed lacus dapibus elementum sed eu lectus.</p>
</div>
);

var Contact = () => (
<div>
<h2>GOT QUESTIONS?</h2>
<p>
The easiest thing to do is post on our <a href='http://forum.kirupa.com'>forums</a>.
</p>
</div>
);
var Stuff = () => (
<div>
<h2>STUFF</h2>
<p>Mauris sem velit, vehicula eget sodales vitae, rhoncus eget sapien:</p>
<ol>
<li>Nulla pulvinar diam</li>
<li>Facilisis bibendum</li>
<li>Vestibulum vulputate</li>
<li>Eget erat</li>
<li>Id porttitor</li>
</ol>
</div>
);

ReactDOM.render(
<Router>
<App>
<Route exact path='/' component={Home} />
<Route path='/Contact' component={Contact} />
<Route path='/Stuff' component={Stuff} />
</App>
</Router>,
destination,
);

NavLink即我们的a元素, 可以指向要跳转到的url, activeClassName可以指定一个在当前页面urlNavLink指向的url相匹配时候的class, 方便做一些样式高亮设计. Route组件则是路由实现的关键组件, 作用是当to属性里面的url匹配到当前页面, 则展示component中的组件.

在新版本中, Route已经变成随处可用的组件了, 可叠加可嵌套. 而且需要用到的组件都是从react-router-dom包里导出. 更多的例子可以去官网示例中查看.

在一般的项目中, 推荐将一级路由配置在页面最外层的组件里, 方便集中管理和维护, 如果内层组件有自己的router, 可以在组件内实现. 这是为了将子组件和主模块解耦. 如果项目需要权限管理, 推荐配置动态路由, 即路由数据由服务器根据个人权限获得. 而且可以根据需要, 将组件进行异步加载, 优化页面首次加载的速度. Redirect为重定向组件, 表示从path转向to, Switch组件即在下级的路由组件中只匹配一次, 由于匹配是按顺序进行, 所以我们的重定向到首页组件需要写在最后一位. exact属性表示精确匹配, 否则是模糊匹配.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div className='right-content'>
<Switch>
{this.state.routeList.map((item, index) => {
if (item.get('to')) {
return <Redirect key={index} path={item.get('url')} exact={item.get('exact')} to={item.get('to')} />;
} else if (item.get('src')) {
return <Route key={index} path={item.get('url')} exact={item.get('exact')} render={() => <AsyncComponent src={item.get('src')} />} />;
} else {
return null;
}
})}
<Route exact path='/' render={() => '欢迎来到首页'} />
<Redirect path='*' to='/' />
</Switch>
{this.props.children}
</div>

react-router原理

hash-router

本质上是基于浏览器提供的window.onhashchange事件, 只要改变location.hash, 就会触发该事件, 进行路由拦截和组件加载判断.

但是为了统一化, history模块也将hash-router封装成了和browser-router一样的使用方式和原理.

browser-router

本来浏览器提供了window.onpopstate来监听浏览器url改变事件, 但是通过js执行history.pushState({},title,url)或者history.replaceState时候, 却不会触发onpopstate事件, 所以只能自己实现一套拦截的体系. react使用的是history模块.
在组件初始化的时候通过history.createBrowserHistory生成一个history对象, 该对象里面有一个事件监听列表和相关事件. 在Link组件中的a标签点击时, 使用preventDefault阻止页面跳转, 然后通过history.push/replace(to)进行跳转url. 在Router组件中的componentWillMount时, 会通过history.listen设置监听, 如果url有变化则通过setState进行修改. 而在使用ReduxPureComponent的情况下, setState不会引起下级组件的更新, 那么在ConnectedRouter中的componentWillMount中, 也添加了history.listen来监听url的更改, 同时通过store.dispatch({type: LOCATION_CHANGE,payload: location})来发送actionreducer中, 这就是为什么引入immutable时, 需要手动设置routerReduceraction.type === LOCATION_CHANGE时候的原因了.

作者

Mosby

发布于

2017-08-02

许可协议

评论