学习自https://github.com/reactjs/react-router-tutorial
简介
React Router 是一个由React创建的强大的路由库,可以帮助我们快速的实现路由功能,保持我们的URL和React组件的同步映射关系.
在解释React Router是如何帮助我们之间,让我们看看在不使用它的情况下是如何创建一个应用程序的.我们将使用ES6/ES2015语法特性,完成我们的示例.
不使用 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的hash值的改变,<App>
会渲染不同的<Child>
.这看起来很好理解,但是也变的复杂.
想象一下现在Inbox有一些嵌套的UI组件,对应不同的URL,可能如下图所示:
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 modules...
import { Router, Route, IndexRoute, Link, hashHistory } 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 history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={Home} />
<Route path="about" component={About} />
<Route path="inbox" component={Inbox} />
</Route>
</Router>
), document.body)
React Router知道怎么创建嵌套UI,我们不用手动的找出哪个<Child>
组件需要被渲染,例如,对于路径/about
它将会创建<App><About /></App>
.
内部,路由器转换你的<Route>
元素到路由配置.但如果你不想用JSX语法,你能使用一个对象代替:
const routes = {
path: '/',
component: App,
indexRoute: { component: Home },
childRoutes: [
{ path: 'about', component: About },
{ path: 'inbox', component: Inbox },
]
}
render(<Router history={history} routes={routes} />, document.body)
添加更多界面
现在我们准备在inbox内部嵌套一个inbox messages组件.
// 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 history={history}>
<Route path="/" component={App}>
<IndexRoute component={Home} />
<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将匹配到这个新的路由规则,并创建如下组件:
<App>
<Inbox>
<Message params={{ id: 'Jkei3c32' }}/>
</Inbox>
</App>
访问/inbox将创建:
<App>
<Inbox>
<InboxStats/>
</Inbox>
</App>
获取URL参数
我们需要知道一些信息好从服务器获取它.Route组件渲染时会注入一些有用的信息,特别是你的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"
.
今天就先学这么多.