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
可以指定一个在当前页面url
和NavLink
指向的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
进行修改. 而在使用Redux
和PureComponent
的情况下, setState
不会引起下级组件的更新, 那么在ConnectedRouter
中的componentWillMount
中, 也添加了history.listen
来监听url
的更改, 同时通过store.dispatch({type: LOCATION_CHANGE,payload: location})
来发送action
到reducer
中, 这就是为什么引入immutable
时, 需要手动设置routerReducer
在action.type === LOCATION_CHANGE
时候的原因了.