react-router是用于实现React项目中路由功能的库,对于构建SPA React项目非常有必要,react-router4.x对react-router整体进行了重写,API也相对于3.x有了很大的改变,可以理解4.x和3.x是两个完全不同的工具,3.x主张集中配置route,4.x则将每一个路由都当做普通React component,因此route的配置会融入到整个项目的代码中,它的作者把这个称之为动态路由。这里重点介绍react-router4.x的使用。
react-router将之前的库拆分成以下三个库:
对于react项目,我们只需要安装 react-router-dom即可:
npm install react-router-dom --save
react-router提供好几种router来满足不同的需求:
其中使用最多的是BrowserRouter和HashRouter,这里用HashRouter举例:
import {HashRouter} from 'react-router-dom';
ReactDOM.render((
<HashRouter>
<App />
</HashRouter>
), document.getElementById('root'))
Route组件是react-router中最重要也是最常用的组件,它通常的作用是当url和组件的path属性匹配时渲染相应的UI组件。
Route可以通过3种方式来指定UI:
<Route component>
import {Route} from 'react-router-dom';
import Page1 from './page1';
export default (props) => {
return (
<div>
<Route path="/page1" component={Page1} />
</div>
);
}
这种方式其实是route通过React.createElement来创建一个component指定组件的实例,需要注意的是如果component组件传入一个inline函数来返回一个组件,那么每次render就会创建一个新的实例,这样就导致已有的组件实例没有销毁,新的实例又创建了,而不是直接更新已有的实例,因此对于这种情况,建议使用下面两种方式。
<Route render>
import {Route} from 'react-router-dom';
export default (props) => {
return (
<div>
<Route path="/page2" render={(props) => (
<div>
page2 yoyoyo
</div>
)} />
</div>
);
}
<Route children>
通过children属性来指定UI组件,接受一个参数为match的函数,使用者可以根据是否匹配path来选择渲染不同的UI组件。import {Route} from 'react-router-dom';
export default (props) => {
return (
<div>
<Route path="/page2" children={({match}) => {
if (match) {
return (<div> match the path</div>);
} else {
return (<div> not match the path</div>);
}
}} />
</div>
);
}
Route组件可以配置如下参数来指定url匹配规则:
path | location.pathname | exact | match? |
---|---|---|---|
/one | /one/two | false | yes |
/one | /one/two | true | no |
|path|location.pathname|match?| |-|-|-|-| |/one/|/one|no| |/one/|/one/|yes| |/one/|/one/two|yes|
Route在指定渲染UI组件时会给组件注入3个props:
match:是一个用描述match情况的对象,主要包含以下内容:
location:用于记录当前location相关描述,通常是下面这个样子:
{
key: 'ac3df4', // not with HashHistory!
pathname: '/somewhere'
search: '?some=search-string',
hash: '#howdy',
state: {
[userDefined]: true
}
}
在history的属性中也有一个history.location,但是通常建议使用这个,因为history下面的location会发生突变,这个不会。
用于将当前locaction重定向到一个新的location,新的location将替换掉history栈中的当前实体。通常用法:
//接受string
<Redirect push to="/somewhere/else"/>
//接受object
<Redirect to={{
pathname: '/login',
search: '?utm=your+face',
state: { referrer: currentLocation }
}}/>
//在switch中使用
<Switch>
<Redirect from='/old-path' to='/new-path'/>
<Route path='/new-path' component={Place}/>
</Switch>
Switch用来包裹Route和Redirect,并render第一个匹配的Route或Redirect。因此它是有排他性的,不使用switch的情况下,会渲染所有匹配的Route或Redirect。
如下所示,如果访问/about,三个组件都会被渲染:
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
如果按照下面的方式来写,往往更能达到用户的期望:
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
</Switch>
Switch中只能使用Route和Redirect子元素
Switch可以设置一个location熟悉来替代当前浏览器location
没有path的Route和没有from的Redirect都可以匹配所有链接
Link类似a标签,用于进行页面跳转,默认是使用push的方式,通常用法如下所示:
<Link to="/courses"/>
<Link to={{
pathname: '/courses',
search: '?sort=name',
hash: '#the-hash',
state: { fromDashboard: true }
}}/>
<Link to="/courses" replace />
NavLink是一种特殊的Link,它可以将样式属性传递给当前组件,如果to设置的path匹配当前URL,最常见的场景就是导航条。基本用法如下:
//设置class
<NavLink
to="/faq"
activeClassName="selected"
>FAQs</NavLink>
//设置属性
<NavLink
to="/faq"
activeStyle={{
fontWeight: 'bold',
color: 'red'
}}
>FAQs</NavLink>
//支持exact和strict属性
<NavLink
exact
strict
to="/profile/"
>Profile</NavLink>
我们也可以设置一个isActive属性来处理一些特殊逻辑:
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>