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 -> About
, App -> Inbox -> Messages -> Message
, App -> 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 同步,并轻松链接到它们。
关于路由配置的文档更深入地描述了该路由器的更多特性。
评论 (0)