页面路由——React-Router

React-Router

简介

React Router 是一个基于 React 之上的强大路由库,它可以让你向应用中快速地添加视图和数据流,同时保持页面与 URL 之间的同步。

使用 React Router

import React from 'react'
import { render } from 'react-dom'

// 首先我们需要导入一些组件...
import { Router, Route, Link } from 'react-router'

// 然后我们从应用中删除一堆代码和
// 增加一些 <Link> 元素...
const App = React.createClass({
  render() {
    return (
      <div>
        <h1>App</h1>
        {/* 把 <a> 变成 <Link> */}
        <ul>
          <li><Link to="/about">About</Link></li>
          <li><Link to="/inbox">Inbox</Link></li>
        </ul>

        {/*
          接着用 `this.props.children` 替换 `<Child>`
          router 会帮我们找到这个 children
        */}
        {this.props.children}
      </div>
    )
  }
})

// 最后,我们用一些 <Route> 来渲染 <Router>。
// 这些就是路由提供的我们想要的东西。
React.render((
  <Router>
    <Route path="/" component={App}>
      <Route path="about" component={About} />
      <Route path="inbox" component={Inbox} />
    </Route>
  </Router>
), document.body)

如果你不熟悉 JSX,也可以用普通对象来替代。

获取 URL 参数

为了从服务器获取 message 数据,我们首先需要知道它的信息。当渲染组件时,React Router 会自动向 Route 组件中注入一些有用的信息,尤其是路径中动态部分的参数。

也可以通过 query 字符串来访问参数。比如访问 /foo?bar=baz可以通过访问 this.props.location.query.bar 从 Route 组件中获取 'baz'的值

基础

YzAfw8.png

添加首页

当URL为/时,我们想渲染一个在 App中的组件。不过此时,App 的 render中的this.prop.children还是undefined。这种情况下我们可以使用 IndexRoute来设置一个默认页面。

让 UI 从 URL 中解耦出来

通过在定义 path 中使用 /messages/:id 替换 messages/:id 在多层前套路由中使用绝对路径的能力让我们对 URL 拥有绝对的掌握。我们无需在 URL 中添加更多的层级。

兼容旧的 URL

使用 <Redirect> 使URL重定向。

进入和离开 Hook

Route 可以定义 onEnteronLeave 两个 hook,这些 hook 会在页面跳转确认时触发一次。这些 hook 对于一些情况非常的有用,例如权限验证或者在路由跳转前将一些数据持久化保存起来。

在路由跳转过程中

  • onLeave 会在所有将离开的路由中触发,从最下层的路由开始直到最外层路由结束。

  • onEnter 会在将进入的路由时触发。

替换配置方式

如果你不想使用 JSX,也可以直接使用原生的 route 数组对象。

路由匹配原理

路由拥有三个属性来决定是否匹配一个URL

  • 嵌套关系

  • 路径语法

  • 优先级

嵌套关系

当一个给定的 URL 被调用时,整个集合中(命中的部分)都会被渲染。嵌套路由被描述成一种树形结构

路径语法

匹配一个(或一部分)URL的一个字符串模式。大部分的路由路径都可以直接按照字面量理解,除了下边的特殊符号

  • :paramName - 匹配一段位于 /?#之后的URL

  • () - 在它内的内容被认为是可选的

  • * - 匹配任意字符直到命中下一个字符或者整个 URL 的末尾

优先级

路由算法会根据定义的顺序自顶向下匹配路由

Histories

React Router是建立在 history 上的。简而言之,一个 history 知道如何去监听浏览器地址栏的变化,并解析这个 URL 转化为 location 对象,然后 router 使用它匹配到路由,最后正确的渲染页面。

  • browserHistory

  • hashHistory

  • createMemoryHistory

使用

browserHistory

他使用浏览器中 History API 用于处理 URL

服务器配置

服务器需要做好处理 URL 的准备。处理应用启动最初的/这样的请求是没问题的,但当用户来回跳转并在/account/123刷新时,服务器就会收到来自 account/123的请求,这时需要处理这个 URL 并响应对应的 JavaScript 代码。

hashHistory

Hash History 使用 URL 中的 hash # 部分去创建形如example.com/#/some/path 的路由。

对比

Hash History 不需要服务器任何配置就可以运行,但是我们不推荐在实际线上环境中使用,因为每一个 web 应用都应该渴望使用 browserHistory。

传递参数

当一个 History 通过应用程序中的 push 或 replace跳转时,他可以在新的 location中存储 location state而不显示在 URL 中,这就像是在一个 HTML 中 post 的表单数据。

createMemoryHistory

Memory History 不会在地址栏被操作或读取。同时它也非常适合测试和其他渲染环境

和另外两种 history 的一点不同是必须创建它,这种方式便于测试。

使用

默认路由 (IndexRoute)

Index Links

如果你在这个 app 中使用 <Link to="/">Home</Link> , 它会一直处于激活状态,因为所有的 URL 的开头都是 / 。 这确实是个问题,因为我们仅仅希望在 Home 被渲染后,激活并链接到它。

如果需要在 Home 路由被渲染后才激活的指向 / 的链接,请使用 <IndexLink to="/">Home</IndexLink>

高级用法

YzAqO0.png

动态路由

React Router 适用于小型网站,也可以支持大型网站。

对于大型应用来说,一个首当其冲的问题就是所需加载的 JavaScript 的大小。程序应当只加载渲染页所需的 JavaScript。

路由是个非常适于做代码分拆的地方:他的责任就是配置好每个 view

React Router 里的路径匹配以及组件加载都是异步完成,不仅允许你延迟加载组件,并且可以延迟加载路由配置。在首次加载包中你只需要有一个路径定义,路由会自动解析剩下的路径。

Route 可以定义 getChildRoutesgetIndexRoutegetComponents这几个函数。他们都是异步执行,并且只有在需要的时候才被调用。称之为“逐渐匹配”。

匹配 URL 并只加载该 URL 对应页面所需的路径配置和组件。

跳转前确认

React Router 它提供一个 routerWillLeave 钩子,使得组件可以拦截正在发生的跳转,或在离开 route 前提示用户。

  1. return false 取消此次跳转

  2. return返回提示信息,在离开 route前提示用户进行确认。

通过在 route 组件中引入 Lifecycle mixin 来安装这钩子

服务端渲染

服务端渲染与客户端渲染有些许不同

  • 发生错误时发送一个 500 的响应

  • 需要重定向时发送一个 30x 的响应

  • 在渲染之前获得数据(用 router 帮你完成这点)

为了迎合这一需求,需要在 <Router />API 下一层使用

  • 使用 match 在渲染之前根据 location 匹配 route

  • 使用 RoutingContext 同步渲染route组件

组件生命周期

路由切换时,组件生命周期的变化情况

1.当用户打开应用 '/' 页面

组件
生命周期

APP

componentDidMount

Home

componentDidMount

Invoice

N/A

Account

N/A

2.当用户从 '/'跳转到 '/invoice/123'

组件
生命周期

App

componentWillReceiveProps, componentDidUpdate

Home

componentWillUnmount

Invoice

componentDidMount

Account

N/A

  • App 从 router 中接收到新的 props,所以触发了两个生命周期方法

  • Home 不再被渲染,所以它将被移除

  • Invoice 首次被挂载

3.当用户从 /invoice/123 跳转到 /invoice/789

组件
生命周期

App

componentWillReceiveProps, componentDidUpdate

Home

N/A

Invoice

componentWillReceiveProps, componentDidUpdate

Account

N/A

4.当从 /invoice/789 跳转到 /accounts/123

组件
生命周期

App

componentWillReceiveProps, componentDidUpdate

Home

N/A

Invoice

componentWillUnmount

Account

componentDidMount

获取数据

我们在 Invoice 组件里实现一个简单的数据获取功能

最后更新于