React Router 学习手册(基础篇)
<p><code></p>
<p>该手册是基于<a href="https://github.com/ReactTraining/react-router" rel="nofollow noreferrer" target="_blank">react-router</a> 和 <a href="http://www.ruanyifeng.com/blog/2016/05/react_router.html" rel="nofollow noreferrer" target="_blank">React Router 使用教程</a> 学习编写而成,可能会有描述不够清楚的地方,大家可自行参考原文,</p>
<p><a href="https://github.com/ReactTraining/react-router" rel="nofollow noreferrer" target="_blank">React Router</a> 为 <a href="https://facebook.github.io/react/" rel="nofollow noreferrer" target="_blank">React</a> 提供了一个完整的路由库,它允许你通过 <code>URl</code> 的变化来控制组件的切换与变化</p>
<p>有关 <a href="http://www.js-code.com/tag/react" title="React" target="_blank">React</a> 全家桶的其余相关文章,可以查看以下链接,会持续更新</p>
<ul>
<li>
<p><a href="https://segmentfault.com/a/1190000007337318">别眨眼看 React</a></p>
</li>
</ul>
<h2 id="articleHeader0">安装</h2>
<p>使用 <a href="https://www.npmjs.com/" rel="nofollow noreferrer" target="_blank">npm</a> 进行安装:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="npm install --save react-router
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs sql"><code>npm <span class="hljs-keyword">install</span> <span class="hljs-comment">--save react-router</span>
</code></pre>
<p>之后在需要用到的地方进行引用,</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="// 需要用到 ES6 编译器,比如 babel
import { Router, Route, Link } from 'react-router'
// 不需要使用编译器
var Router = require('react-router').Router
var Route = require('react-router').Route
var Link = require('react-router').Link" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="javascript hljs"><code class="js"><span class="hljs-comment">// 需要用到 ES6 编译器,比如 babel</span>
<span class="hljs-keyword">import</span> { Router, Route, Link } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router'</span>
<span class="hljs-comment">// 不需要使用编译器</span>
<span class="hljs-keyword">var</span> Router = <span class="hljs-built_in">require</span>(<span class="hljs-string">'react-router'</span>).Router
<span class="hljs-keyword">var</span> Route = <span class="hljs-built_in">require</span>(<span class="hljs-string">'react-router'</span>).Route
<span class="hljs-keyword">var</span> Link = <span class="hljs-built_in">require</span>(<span class="hljs-string">'react-router'</span>).Link</code></pre>
<p>当然也可以使用 <code>script</code> 标签进行引用:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="<a href="http://www.js-code.com/tag/button" title="button" target="_blank">button</a>" <a href="http://www.js-code.com/tag/class" title="class" target="_blank">class</a>="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="top" target="_blank">top</a>" data-clipboard-<a href="http://www.js-code.com/tag/text" title="text" target="_blank">text</a>="<script src="https://unpkg.com/react-router/umd/ReactRouter.min.js"></script><br />
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs xml"><code><span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/react-router/umd/ReactRouter.min.js"</span>></span><span class="undefined"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
</code></pre>
<p>之后可以通过 <code>w<a href="http://www.js-code.com/tag/in" title="in" target="_blank">in</a><a href="http://www.js-code.com/tag/do" title="do" target="_blank">do</a>w.<a href="http://www.js-code.com/tag/react" title="React" target="_blank">React</a>Router</code> 进行调用</p>
<h2 id="articleHeader1">概述</h2>
<h4>样例概述</h4>
<p>当我们想要实现类似信息系统的界面,进入到收件箱选择查看具体信息 <code>1234</code> 的时候,界面路由如下:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="path: /inbox/messages/1234
+---------+------------+------------------------+
| About | Inbox | |
+---------+ +------------------------+
| Compose Reply Reply All Archive |
+-----------------------------------------------+
|Movie tomorrow| |
+--------------+ Subject: TPS Report |
|TPS Report From: boss@big.co |
+--------------+ |
|New Pull Reque| So ... |
+--------------+ |
|... | |
+--------------+--------------------------------+" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs ruby"><code><span class="hljs-symbol">path:</span> /inbox/messages/<span class="hljs-number">1234</span>
+---------+------------+------------------------+
<span class="hljs-params">| About |</span> Inbox <span class="hljs-params">| |</span>
+---------+ +------------------------+
<span class="hljs-params">| Compose Reply Reply All Archive |</span>
+-----------------------------------------------+
<span class="hljs-params">|Movie tomorrow|</span> <span class="hljs-params">|
+--------------+ Subject: TPS Report |</span>
<span class="hljs-params">|TPS Report From: boss@big.co |</span>
+--------------+ <span class="hljs-params">|
|</span>New Pull Reque<span class="hljs-params">| So ... |</span>
+--------------+ <span class="hljs-params">|
|</span>... <span class="hljs-params">| |</span>
+--------------+--------------------------------+</code></pre>
<p>应该实现以下几种路由:</p>
<table>
<thead>
<tr>
<th align="center">URL</th>
<th align="center">Components</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center"><code>/</code></td>
<td align="center"><code>App -> Home</code></td>
</tr>
<tr>
<td align="center"><code>/about</code></td>
<td align="center"><code>App -> About</code></td>
</tr>
<tr>
<td align="center"><code>/<a href="http://www.js-code.com/tag/in" title="in" target="_blank">in</a>box</code></td>
<td align="center"><code>App -> In<a href="http://www.js-code.com/tag/do" title="do" target="_blank">do</a>x</code></td>
</tr>
<tr>
<td align="center"><code>/inbox/messages/:id</code></td>
<td align="center"><code>App -> Inbox -> Message</code></td>
</tr>
</tbody>
</table>
<h4>使用 <code>react-router</code> 进行实现</h4>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="<a href="http://www.js-code.com/tag/button" title="button" target="_blank">button</a>" <a href="http://www.js-code.com/tag/class" title="class" target="_blank">class</a>="copyCode code-tool" data-toggle="tooltip" data-placement="<a href="http://www.js-code.com/tag/top" title="top" target="_blank">top</a>" data-clipboard-<a href="http://www.js-code.com/tag/text" title="text" target="_blank">text</a>="<br />
// 省略部分组件定义<br />
<a href="http://www.js-code.com/tag/const" title="const" target="_blank">const</a> App = React.create<a href="http://www.js-code.com/tag/class" title="Class" target="_blank">Class</a>({<br />
render() {<br />
<a href="http://www.js-code.com/tag/return" title="return" target="_blank">return</a> (</p>
<div>
<h1>App</h1>
<p> {/* 使用 `<Link>` 标签进行路由跳转 */}</p>
<ul>
<li><Link to="/about">About</Link></li>
<li><Link to="/inbox">Inbox</Link></li>
</ul>
<p> {<a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a>.props.children}
</div>
<p> )<br />
}<br />
})</p>
<p>const About = ...;<br />
const Home = ...;</p>
<p>const Inbox = (props) => {<br />
<a href="http://www.js-code.com/tag/return" title="return" target="_blank">return</a> (</p>
<div>
<h2>Inbox</h2>
<p> {props.children}
</p></div>
<p> )<br />
}<br />
<a href="http://www.js-code.com/tag/const" title="const" target="_blank">const</a> IndexStatus = ...;<br />
<a href="http://www.js-code.com/tag/const" title="const" target="_blank">const</a> Message = ...;</p>
<p>// <Router> 是一个 React 组件<br />
// <Router> 同时也是 <Route> 的一个容器,路由规则使用 <Route> 进行定义<br />
render((<br />
<Router history={hasHistory}><br />
<Route path="/" component={App}><br />
{/*<br />
当我们访问 `/` 的时候不会有加载任何子组件,组件 `<App>` 的 `<a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a>.props.children`为 `<a href="http://www.js-code.com/tag/undefined" title="undefined" target="_blank">undefined</a>`,<br />
所以我们使用 `<IndexRoute>` 来指定默认加载的子组件<br />
*/}<br />
<IndexRoute compoent={Home} ></IndexRoute><br />
<Route path="about" component={About} ></Route><br />
<Route path="inbox" component={Inbox}><br />
<IndexRoute component={IndexStatus} ></IndexRoute><br />
{ /* 匹配 `/index/messages/123` 路由*/ }<br />
<Route path="messages/:id" component={Message} ></Route><br />
{ /* 当然我们可以直接匹配 `messages/123`,但不破坏路由组件结构 */}<br />
<Route component={Inbox}><br />
<Route path="messages/:id" component={Message} ></Route><br />
</Route><br />
</Route><br />
</Route><br />
</Router><br />
), document.body)<br />
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs xml"><code>
// 省略部分组件定义
const App = React.createClass({
render() {
return (
<span class="hljs-tag"><<span class="hljs-name">div</span>></span>
<span class="hljs-tag"><<span class="hljs-name">h1</span>></span>App<span class="hljs-tag"></<span class="hljs-name">h1</span>></span>
{/* 使用 `<span class="hljs-tag"><<span class="hljs-name">Link</span>></span>` 标签进行路由跳转 */}
<span class="hljs-tag"><<span class="hljs-name">ul</span>></span>
<span class="hljs-tag"><<span class="hljs-name">li</span>></span><span class="hljs-tag"><<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/about"</span>></span>About<span class="hljs-tag"></<span class="hljs-name">Link</span>></span><span class="hljs-tag"></<span class="hljs-name">li</span>></span>
<span class="hljs-tag"><<span class="hljs-name">li</span>></span><span class="hljs-tag"><<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/inbox"</span>></span>Inbox<span class="hljs-tag"></<span class="hljs-name">Link</span>></span><span class="hljs-tag"></<span class="hljs-name">li</span>></span>
<span class="hljs-tag"></<span class="hljs-name">ul</span>></span>
{this.props.children}
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
)
}
})
const About = ...;
const Home = ...;
const Inbox = (props) => {
return (
<span class="hljs-tag"><<span class="hljs-name">div</span>></span>
<span class="hljs-tag"><<span class="hljs-name">h2</span>></span>Inbox<span class="hljs-tag"></<span class="hljs-name">h2</span>></span>
{props.children}
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
)
}
const IndexStatus = ...;
const Message = ...;
// <span class="hljs-tag"><<span class="hljs-name">Router</span>></span> 是一个 React 组件
// <span class="hljs-tag"><<span class="hljs-name">Router</span>></span> 同时也是 <span class="hljs-tag"><<span class="hljs-name">Route</span>></span> 的一个容器,路由规则使用 <span class="hljs-tag"><<span class="hljs-name">Route</span>></span> 进行定义
render((
<span class="hljs-tag"><<span class="hljs-name">Router</span> <span class="hljs-attr">history</span>=<span class="hljs-string">{hasHistory}</span>></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{App}</span>></span>
{/*
当我们访问 `/` 的时候不会有加载任何子组件,组件 `<span class="hljs-tag"><<span class="hljs-name">App</span>></span>` 的 `this.props.children`为 `undefined`,
所以我们使用 `<span class="hljs-tag"><<span class="hljs-name">IndexRoute</span>></span>` 来指定默认加载的子组件
*/}
<span class="hljs-tag"><<span class="hljs-name">IndexRoute</span> <span class="hljs-attr">compoent</span>=<span class="hljs-string">{Home}</span> /></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"about"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{About}</span> /></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"inbox"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Inbox}</span>></span>
<span class="hljs-tag"><<span class="hljs-name">IndexRoute</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{IndexStatus}</span> /></span>
{ /* 匹配 `/index/messages/123` 路由*/ }
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"messages/:id"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Message}</span> /></span>
{ /* 当然我们可以直接匹配 `messages/123`,但不破坏路由组件结构 */}
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Inbox}</span>></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"messages/:id"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Message}</span> /></span>
<span class="hljs-tag"></<span class="hljs-name">Route</span>></span>
<span class="hljs-tag"></<span class="hljs-name">Route</span>></span>
<span class="hljs-tag"></<span class="hljs-name">Route</span>></span>
<span class="hljs-tag"></<span class="hljs-name">Router</span>></span>
), document.body)
</code></pre>
<h2 id="articleHeader2">Route 详解</h2>
<p>一个路由由三个属性来决定它是否能匹配上 <code>URL</code>:</p>
<ul>
<li>
<p>嵌套结构</p>
</li>
<li>
<p><code>Path</code> 属性</p>
</li>
<li>
<p>优先级</p>
</li>
</ul>
<h4>嵌套</h4>
<p>当一个 <code>URL</code> 被调用,React Router 允许你通过嵌套路由 (Nested routes) 的方式来声明将要被渲染的一系列嵌套组件,嵌套路由是类树状结构 (tree-like structure),React Router 通过 <code>route config</code> 的顺序去匹配 <code>URL</code></p>
<blockquote>
<p><a href="https://github.com/ReactTraining/react-router/blob/master/docs/Glossary.md#routeconfig" rel="nofollow noreferrer" target="_blank">RouteConfig</a> 是 React Router 内部用来指定 router 顺序的<a href="http://www.js-code.com/tag/%e6%95%b0%e7%bb%84" title="数组" target="_blank">数组</a></p>
</blockquote>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="<Router history={hashHistory}><br />
<Route path="/" component={App}><br />
<Route path="/repos" component={Repos}></Route><br />
<Route path="/about" component={About}></Route><br />
</Route><br />
</Router>" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs xml"><code><span class="hljs-tag"><<span class="hljs-name">Router</span> <span class="hljs-attr">history</span>=<span class="hljs-string">{hashHistory}</span>></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{App}</span>></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/repos"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Repos}/</span>></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/about"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{About}/</span>></span>
<span class="hljs-tag"></<span class="hljs-name">Route</span>></span>
<span class="hljs-tag"></<span class="hljs-name">Router</span>></span></code></pre>
<h4>
<code>Path</code> 语法</h4>
<ul>
<li>
<p><code>:paramName</code>,匹配 <code>URL</code> 的一个部分,直到遇到下一个/、?、#</p>
</li>
<li>
<p><code>()</code>,表示URL的这个部分是可选的</p>
</li>
<li>
<p><code>*</code>,匹配任意字符(非贪婪模式),直到模式里面的下一个字符为</p>
</li>
<li>
<p><code>**</code>,匹配任意字符(贪婪模式),直到下一个/、?、#为止</p>
</li>
</ul>
<blockquote>
<p>贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配<br />非贪婪模式:在整个表达式匹配成功的前提下,尽可能多的匹配</p>
</blockquote>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="<Route path="/hello/:name"> // 匹配 /hello/michael 和 /hello/ryan<br />
<Route path="/hello(/:name)"> // 匹配 /hello, /hello/michael, 和 /hello/ryan<br />
<Route path="/files/*.*"> // 匹配 /files/hello.jpg 和 /files/hello.html<br />
<Route path="/**/*.jpg"> // 匹配 /files/hello.jpg 和 /files/path/to/file.jpg" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs lua"><code><Route <span class="hljs-built_in">path</span>=<span class="hljs-string">"/hello/:name"</span>> // 匹配 /hello/michael 和 /hello/ryan
<Route <span class="hljs-built_in">path</span>=<span class="hljs-string">"/hello(/:name)"</span>> // 匹配 /hello, /hello/michael, 和 /hello/ryan
<Route <span class="hljs-built_in">path</span>=<span class="hljs-string">"/files/*.*"</span>> // 匹配 /files/hello.jpg 和 /files/hello.html
<Route <span class="hljs-built_in">path</span>=<span class="hljs-string">"/**/*.jpg"</span>> // 匹配 /files/hello.jpg 和 /files/<span class="hljs-built_in">path</span>/to/file.jpg</code></pre>
<h4>优先级</h4>
<p>React Router 是通过从上到下的顺序匹配路由的,所以应该尽量保证同级路由的第一个路由不会匹配上所有可能的 <code>Path</code>,例如:</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="<Route path="/comments" ... ></span><br />
<Redirect from="/comments" ... ></Redirect> // 这一条路由规则是不会执行的,以为上一条路由已经匹配了所有路径为 `/comments`" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs typescript"><code><Route path=<span class="hljs-string">"/comments"</span> ... />
<Redirect <span class="hljs-keyword">from</span>=<span class="hljs-string">"/comments"</span> ... /> <span class="hljs-comment">// 这一条路由规则是不会执行的,以为上一条路由已经匹配了所有路径为 `/comments`</span></code></pre>
<h2 id="articleHeader3">Histories</h2>
<p>React Router 构建于 <a href="https://github.com/mjackson/history" rel="nofollow noreferrer" target="_blank">history</a>,简而言之,React Router <code><a href="http://www.js-code.com/tag/history" title="history" target="_blank">history</a></code> 属性用于监听浏览器地址栏的变化,<br />并将 <code>URL</code> 解析后放入进 <code><a href="http://www.js-code.com/tag/location" title="location" target="_blank">location</a></code> 对象中,给 React Router 提供匹配,</p>
<p>我们使用如下方式从 React Router Package 中引用,</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="import { browserHistory } from 'react-router'
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs typescript"><code><span class="hljs-keyword">import</span> { browserHistory } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router'</span>
</code></pre>
<p>然后在 <code><Router></code> 中使用,</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="render(
<Router history={browserHistory} routes={routes} ></span>,<br />
document.getElementById('app')<br />
)" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs lisp"><code>render(
<span class="hljs-name"><Router</span> history={browserHistory} routes={routes} />,
document.getElementById('app')
)</code></pre>
<p>有三种 <code><a href="http://www.js-code.com/tag/history" title="history" target="_blank">history</a></code> 属性类型:</p>
<p><strong><code>browserHistory</code></strong></p>
<p>Browser history 是通过 <code>URL</code> 变化来改变路由的,它是背后调用的是浏览器的 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/History" rel="nofollow noreferrer" target="_blank">History</a>,</p>
<p>但是,使用 Browser history 是需要<a href="https://github.com/ReactTraining/react-router/blob/master/docs/guides/Histories.md#configuring-your-server" rel="nofollow noreferrer" target="_blank">配置你的服务器</a></p>
<p><strong><code>hashHistory</code></strong></p>
<p>Hash history 使用哈希符 (<code>#</code>) 作为 <code>URL</code> 的一部分,路由通过哈希符的部分进行切换,<code>URL</code> 的形式类似于,<code>example.com/#/some/path</code>,</p>
<p><em>我该使用 <code>hashHistory</code> 么?</em></p>
<p>Hash history 不需要你配置服务器即可使用,当你刚刚开始使用 React Router 的时候,就是用它吧,但是一般来说,生产环境下的 web 应用应该使用 <code>browserHistory</code> 来保持 <code>URLs</code> 的整洁度,并且 <code>hashHistory</code> 是不支持服务端渲染的</p>
<p>实际使用当中,我们会发现具体的 <code>URL</code> 可能为 <code>example.com/#/some/path?_k=ckuvup</code>,</p>
<p>所以 <em><code>?_k=ckuvup</code> 是垃圾代码什么</em> ?</p>
<p>当我们使用 web 应用的时候,浏览器记录 (history) 通过 <code>push</code> 或者 <code>replace</code> 来产生变换,浏览器记录会存储一个地址状态 (<a href="http://www.js-code.com/tag/location" title="location" target="_blank">location</a> state),但并不会体现在 <code>URL</code> 中,</p>
<blockquote>
<p>相关的 <a href="http://www.js-code.com/tag/api" title="API" target="_blank">API</a> 可以参考 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/History" rel="nofollow noreferrer" target="_blank">History</a></p>
</blockquote>
<p>而在 <a href="http://www.js-code.com/tag/dom" title="DOM" target="_blank">DOM</a> <a href="http://www.js-code.com/tag/api" title="API" target="_blank">API</a> 中,改变 Hash history 的方式仅仅是通过 <code><a href="http://www.js-code.com/tag/window" title="window" target="_blank">window</a>.location.hash = <a href="http://www.js-code.com/tag/new" title="new" target="_blank">new</a>Hash</code>,这并没有办法保存地址状态,但是我们希望所有的历史记录都能够使用地址状态,所以我们为每一个地址产生一个独一无二的键值用以表示地址状态,当我们在浏览器中点击后退或者前进的时候,我们就有办法来之前的地址状态了</p>
<p><strong><code>createMemoryHistory</code></strong></p>
<p>Memory history 并不会从地址栏中操作或是读取,它能够帮助我们完成服务器端的渲染,或者用于测试以及其他渲染环境 (比如 React Native),和其他两种方式不一样的是,我们需要在内存中创建 <code>history</code> 对象来使用,</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const history = createMemoryHistory(loaction)
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs lisp"><code>const history = createMemoryHistory(<span class="hljs-name">loaction</span>)
</code></pre>
<h2 id="articleHeader4">Index Routes and Index Links</h2>
<h4>Index Routes</h4>
<p>考虑以下代码,</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="<Router><br />
<Route path="/" component={App}><br />
<Route path="accounts" component={Accounts}></Route><br />
<Route path="statements" component={Statements}></Route><br />
</Route><br />
</Router>" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs xml"><code><span class="hljs-tag"><<span class="hljs-name">Router</span>></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{App}</span>></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"accounts"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Accounts}/</span>></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"statements"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Statements}/</span>></span>
<span class="hljs-tag"></<span class="hljs-name">Route</span>></span>
<span class="hljs-tag"></<span class="hljs-name">Router</span>></span></code></pre>
<p>当我们访问 <code>/</code> 的时候不会有加载任何子组件,组件 <code><App></code> 的<code><a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a>.props.children</code> 为 <code><a href="http://www.js-code.com/tag/undefined" title="undefined" target="_blank">undefined</a></code>,</p>
<p>当然你可以使用 <code>{<a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a>.props.children || <Home />}</code> 来定义渲染默认组件,</p>
<p>但 <code>Home</code> 并没有出现在路由当中,所以这样写并不是非常直观,因此可以使用 <code><IndexRoute></code> 来指定当指定子组件不存在时加载默认的子组件,</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="<Router><br />
<Route path="/" component={App}><br />
<IndexRoute component={Home}></IndexRoute><br />
<Route path="accounts" component={Accounts}></Route><br />
<Route path="statements" component={Statements}></Route><br />
</Route><br />
</Router>" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs xml"><code><span class="hljs-tag"><<span class="hljs-name">Router</span>></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{App}</span>></span>
<span class="hljs-tag"><<span class="hljs-name">IndexRoute</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Home}/</span>></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"accounts"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Accounts}/</span>></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"statements"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Statements}/</span>></span>
<span class="hljs-tag"></<span class="hljs-name">Route</span>></span>
<span class="hljs-tag"></<span class="hljs-name">Router</span>></span></code></pre>
<h4>Redirect and Index Redirects</h4>
<p>我们可以使用 <code><Redirect></code> 组件来定义从一个路由自动跳转至另一个路由,</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="<Route path="inbox" component={Inbox}><br />
{/* 从 /inbox/messages/:id 跳转到 /messages/:id */}<br />
<Redirect from="messages/:id" to="/messages/:id" /><br />
</Route>" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs javascript"><code><Route path=<span class="hljs-string">"inbox"</span> component={Inbox}>
{<span class="hljs-comment">/* 从 /inbox/messages/:id 跳转到 /messages/:id */</span>}
<Redirect <span class="hljs-keyword">from</span>=<span class="hljs-string">"messages/:id"</span> to=<span class="hljs-string">"/messages/:id"</span> />
<span class="xml"><span class="hljs-tag"></<span class="hljs-name">Route</span>></span></span></code></pre>
<p>考虑以下代码,</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="<Route path="/" component={App}><br />
<Route path="welcome" component={Welcome} ></Route><br />
<Route path="about" component={About} ></Route><br />
</Route>" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs xml"><code><span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{App}</span>></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"welcome"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Welcome}</span> /></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"about"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{About}</span> /></span>
<span class="hljs-tag"></<span class="hljs-name">Route</span>></span></code></pre>
<p>当我们希望访问 <code>/</code> 的时候自动跳转至 <code>welcome</code> ,即当我们访问跟路由 <code>/</code> 的时候从定向为其他组件,我们可以使用 <code><IndexRedirect></code> 组件,</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="<Route path="/" component={App}><br />
<IndexRedirect to="/welcome" ></IndexRedirect><br />
<Route path="welcome" component={Welcome} ></Route><br />
<Route path="about" component={About} ></Route><br />
</Route>" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs xml"><code><span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{App}</span>></span>
<span class="hljs-tag"><<span class="hljs-name">IndexRedirect</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/welcome"</span> /></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"welcome"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{Welcome}</span> /></span>
<span class="hljs-tag"><<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"about"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">{About}</span> /></span>
<span class="hljs-tag"></<span class="hljs-name">Route</span>></span></code></pre>
<h4>Index Links</h4>
<p>当我们想点击一个链接跳转至根路由 <code>/</code> , 也许我们会这么写</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="<Link to="/">Home</Link><br />
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs xml"><code><span class="hljs-tag"><<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>></span>Home<span class="hljs-tag"></<span class="hljs-name">Link</span>></span>
</code></pre>
<p>实际上它会匹配任何以 <code>/</code> 开始的子路由, </p>
<p>当我们只希望渲染 <code>Home</code> 相关的组件, 我们应该这么写</p>
<div class="widget-codetool" style="display:none;">
<div class="widget-codetool--inner">
<span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br />
<span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="<IndexLink to="/">Home</IndexLink><br />
" title="" data-original-title="复制"></span>
</div>
</p></div>
<pre class="hljs xml"><code><span class="hljs-tag"><<span class="hljs-name">IndexLink</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>></span>Home<span class="hljs-tag"></<span class="hljs-name">IndexLink</span>></span>
</code></pre>
<h2 id="articleHeader5">Enter and Leave Hooks</h2>
<p>路由组件 (Route) 都拥有 <code>onEnter</code> 和 <code>onLeave</code> 钩子,当一个路由被触发时,进入该路由时触发 <code>onEnter</code> ,离开该路由时触发 <code>onLeave</code>,这两个钩子非常的有用,比如当进入一个路由时,需要先判断时候授权,就会可以使用 <code>onEnter</code>,</p>
<p>在路由跳转过程中,<code>onLeave</code> hook 会在所有将离开的路由中触发,从最下层的子路由开始直到最外层父路由结束,然后 <code>onEnter</code> hook会从最外层的父路由开始直到最下层子路由结束,</p>
<p>回到概述中的例子,如果我们的路由从 <code>/messages/5</code> 跳转到 <code>/about</code>,下面是这些 hook 的执行顺序:</p>
<ul>
<li>
<p><code>/messages/:id</code> 的 <code>onLeave</code></p>
</li>
<li>
<p><code>/inbox</code> 的 <code>onLeave</code></p>
</li>
<li>
<p><code>/about</code> 的 <code>onEnter</code></p>
</li>
</ul>
<p>至此基础篇完结,之后我会给大家带来进阶篇,欢迎大家持续关注,</p>
<p>同时如果文章中有任何错误,欢迎大家指出,好的文章需要你的支持,谢谢</p>
<p></code></p>