React Router 简介

Flying
2016-01-06 / 0 评论 / 87 阅读 / 正在检测是否收录...

React Router 是一个建立在 React 之上的强大路由库,可帮助你以令人难以置信的速度添加新屏幕和流到你的应用程序中,同时保持 URL 与页面上显示的内容同步。

为了说明 React Router 将为你解决的问题,让我们构建一个没有它的小应用程序。

注意:本文介绍的 React Router 版本为 1.0.0

不使用 React Router

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

const About = React.createClass({/*...*/})
const Inbox = React.createClass({/*...*/})
const Home = React.createClass({/*...*/})

const App = React.createClass({
  getInitialState() {
    return {
      route: window.location.hash.substr(1)
    }
  },

  componentDidMount() {
    window.addEventListener('hashchange', () => {
      this.setState({
        route: window.location.hash.substr(1)
      })
    })
  },

  render() {
    let Child
    switch (this.state.route) {
      case '/about': Child = About; break;
      case '/inbox': Child = Inbox; break;
      default:      Child = Home;
    }

    return (
      <div>
        <h1>App</h1>
        <ul>
          <li><a href="#/about">About</a></li>
          <li><a href="#/inbox">Inbox</a></li>
        </ul>
        <Child/>
      </div>
    )
  }
})

render(<App />, document.body)

当 URL 的哈希部分发生变化时,<App> 将通过分支到 this.state.route 渲染一个不同的 <Child>。很简单的东西。但它很快就变得复杂了。

现在想象一下,Inbox 在不同的 url 上有一些嵌套的 UI,可能像下面这样:

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 ...                       |
+--------------+                                |
|...           |                                |
+--------------+--------------------------------+

当不查看消息时,可能会显示一个统计页面:

path: /inbox

+---------+------------+------------------------+
| About   |    Inbox   |                        |
+---------+            +------------------------+
| Compose    Reply    Reply All    Archive      |
+-----------------------------------------------+
|Movie tomorrow|                                |
+--------------+   10 Unread Messages           |
|TPS Report    |   22 drafts                    |
+--------------+                                |
|New Pull Reque|                                |
+--------------+                                |
|...           |                                |
+--------------+--------------------------------+

我们必须使我们的 URL 解析变得更加智能,我们将以大量的代码来确定在任何给定的 URL 上 渲染嵌套组件的哪个分支 :App -> AboutApp -> Inbox -> Messages -> MessageApp -> Inbox -> Messages -> Stats,等等。

使用 React Router

让我们使用 React Router 重构我们的应用程序。

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

// First we import some components...
import { Router, Route, Link } from 'react-router'

// Then we delete a bunch of code from App and
// add some <Link> elements...
const App = React.createClass({
  render() {
    return (
      <div>
        <h1>App</h1>
        {/* change the <a>s to <Link>s */}
        <ul>
          <li><Link to="/about">About</Link></li>
          <li><Link to="/inbox">Inbox</Link></li>
        </ul>

        {/*
          next we replace `<Child>` with `this.props.children`
          the router will figure out the children for us
        */}
        {this.props.children}
      </div>
    )
  }
})

// Finally, we render a <Router> with some <Route>s.
// It does all the fancy routing stuff for us.
render((
  <Router>
    <Route path="/" component={App}>
      <Route path="about" component={About} />
      <Route path="inbox" component={Inbox} />
    </Route>
  </Router>
), document.body)

React Router 知道如何为我们构建嵌套 UI,所以我们不需要手动确定要渲染哪个 <Child> 组件。例如,对于完整路径 /about,它将构建 <App>< about /></App>

在内部,路由器将你的元素层次结构转换为路由配置。但是如果你不了解 JSX,你可以使用普通对象:

const routes = {
  path: '/',
  component: App,
  childRoutes: [
    { path: 'about', component: About },
    { path: 'inbox', component: Inbox },
  ]
}

render(<Router routes={routes} />, document.body)

添加更多 UI

好了,现在我们准备在收件箱 UI 中嵌套收件箱消息。

// Make a new component to render inside of Inbox
const Message = React.createClass({
  render() {
    return <h3>Message</h3>
  }
})

const Inbox = React.createClass({
  render() {
    return (
      <div>
        <h2>Inbox</h2>
        {/* Render the child route component */}
        {this.props.children}
      </div>
    )
  }
})

render((
  <Router>
    <Route path="/" component={App}>
      <Route path="about" component={About} />
      <Route path="inbox" component={Inbox}>
        {/* add some nested routes where we want the UI to nest */}
        {/* render the stats page when at `/inbox` */}
        <IndexRoute component={InboxStats}/>
        {/* render the message component at /inbox/messages/123 */}
        <Route path="messages/:id" component={Message} />
      </Route>
    </Route>
  </Router>
), document.body)

现在访问像 inbox/messages/Jkei3c32 这样的 url 将匹配新的路由,并为你构建以下内容:

<App>
  <Inbox>
    <Message params={ {id: 'Jkei3c32'} } />
  </Inbox>
</App>

访问 /inbox 将构建以下内容:

'<App>
  <Inbox>
    <InboxStats />
  </Inbox>
</App>

获取 URL 参数

我们需要知道一些关于消息的信息,以便从服务器获取它。在渲染时,路由组件会注入一些有用的属性,特别是来自路径动态段的参数。在我们的例子中是 :id

const Message = React.createClass({

  componentDidMount() {
    // from the path `/inbox/messages/:id`
    const id = this.props.params.id

    fetchMessage(id, function (err, message) {
      this.setState({ message: message })
    })
  },

  // ...

})

你也可以从查询字符串中获取参数。如果你访问 /foo?Bar=baz,你可以访问 this.props.location.query.Bar=baz 从你的路由组件中获取 "baz" 的值。

这就是 React Router 的要点。应用程序的 UI 是盒子里的盒子;现在,你可以保持这些框与 URL 同步,并轻松链接到它们。

关于路由配置的文档更深入地描述了该路由器的更多特性。

参考文档

React Router

8

评论 (0)

取消