React-Router,V4

之前学习了第三版的react-router,可是第四版的改动太大了,设计理念和基本用法也不同了,完全可以看作另一个路由插件来学习。

react-router现在分为两个部分。一个是针对浏览器运行的react-router-dom。一个是针对React Native应用的react-router-native。今天先写一篇针对web环境的笔记。要在浏览器端使用react-router V4,直接安装react-router-dom即可,他会自动下载react-router作为依赖。

npm i react-router-dom --save

大多数的路由插件都是在应用初始化的时候配置路由规则,react-router第四版之前也是这样:我们先在js中定义好Router中路径和组件的关联,然后导入应用中。也就是说,对整个应用而言,路由是静态的,写死的。

但是第四版,作者对插件做了大幅改动,他们称之为‘动态路由’。此时<Route>就和React的组件一样,可根据需要生成和销毁,可嵌套在其他组件中。而<Route>本身会将其path特性的路径和当前url匹配,如果匹配成功就渲染UI。所以从效用上,<Route>标签和React的视图组件完全一样,除了多了个路由功能。

--开始---

<Route>

<Route>是React-Router最重要的组件。它有个path特性,如果path和当前url匹配,它会渲染视图,至于渲染什么东西,主要看<Route>中的render方法:

1.component:url匹配时渲染component指定的组件。

<Route exact path="/" component={Home}/>

2.render:函数,url匹配时返回JSX作渲染。

1     <Route exact path={match.url} render={() => (
2       <h3>Please select a topic.</h3>
3     )}/>

3.chidlren:函数,不管url是否匹配,都返回JSX进行渲染。不匹配时match === null。

 1 <ul>
 2   <ListItemLink to="/somewhere"/>
 3   <ListItemLink to="/somewhere-else"/>
 4 </ul>
 5 
 6 const ListItemLink = ({ to, ...rest }) => (
 7   <Route path={to} children={({ match }) => (
 8     <li className={match ? 'active' : ''}>
 9       <Link to={to} {...rest}/>
10     </li>
11   )}/>
12 )

如上,ListItemLink返回一个<Route>,这个<Route>组件将被渲染成<li>。url匹配的<li>将添加active样式。

并且,这三个方法都可以传入三个route props,他们都携带和当前路由有关的信息:

match:是个对象,带有params、url、isExact、path四个属性.

params(obj):当前url动态路径的参数。

isExact:url是否完全匹配:

url(string):当前url的匹配部分。

path(string):用于匹配的路径。

history:初学的时候可以先不管它。虽然对外暴露为一个route props。文档提到,‘history’和‘history object’都指向一个叫‘history package’的东西。它是除了React外,ReactRouter另一个主要依赖。它提供了在不同环境下在js层管理session history的实现。相关的history术语还有“browser history”、“hash history” 、“memory history”,这些history对象都有一只的典型的属性和方法,详见history.

location:其意义和location.href一样。表示app的当前位置,或将要去往哪(对其赋值)。它是一个对象形式,如:

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

这个对象将在上面提到的route的三个渲染方法中出现,作为其prop。在withRoute中也出现。

<Router>:V4中所有Router组件都基于这个底层实现

<BrowserRouter>

<HashRouter>

<MemoryRouter>

<NativeRouter>

<StaticRouter>

这几个Router是react-router应用中使用率比较高的,不过目前看最常用的是<BrowserRouter>和<HashRouter>。

前面提到,v4之前都采用声明式路由,但v4开始“路由即组件”,路由组件和app的组件更深入地耦合了,看一个例子:

 1  const Nav = ()=>(
 2   <Router>
 3     <div>
 4       <ul>
 5       <li><Link to='/home' >Home</Link></li>
 6       <li><Link to='/about'>About</Link></li>
 7       <li><Link to='/else'>Else</Link></li>
 8       </ul>
 9  
10       <Route path='/home' component={Home} />
11       <Route path='/about' component={About} />
12       <Route path='/else' component={Else} />
13      </div>
14   </Router>
15 );
16 
17  export default Nav;

在v3中,由于路由规则是预先定义好的,所以只要url跳到某个路径,页面就会重新渲染(跳转)。但是v4中Link和Route必须在同一个Router下,Link点击后Router才会响应并渲染。

如果把Link放到一个Nav组件,把Route放到一个Container组件,然后将他们导入App。

App>Nav+Container

点击Nav中的Link,Container中的Route将不会渲染。这个是需要注意的。

另外,Route也能接受动态参数。

<Route path="list/:id"></Route>

<Link to="list/12"></Link>

获取参数值:{ this.props.match.params.id }

<Switch>

React-Router中提供的Switch组件,意义上和一部的switch语句一样,会将第一个匹配的Route渲染出来。

直接使用一组<Route>和将一组<Route>包含在<Switch>中有什么区别呢?

*纯粹是用一组Route,只要path和url匹配,Route就会渲染出来。如果有两个Route的path都匹配url,这两个Route都会被渲染。

*使用<Switch>来包裹一组Route,只有第一个匹配的Route会被渲染。

嵌套:

由上面的例子可知,Router>Link+Route的模式中,Route充当了视图(或者说页面)的角色,子级的Router>Link+Route可以嵌套在一个Route绑定的组件中,从而达到嵌套路由的目的。

不过此时子级路由的Link和Route的路径要写绝对路径。