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的路径要写绝对路径。