react-router
from:http://www.ruanyifeng.com/blog/2016/05/react_router.html?utm_source=tool.lu
官方示例:https://github.com/penguinab/react-router-tutorial
Router
组件本身只是一个容器,真正的路由要通过Route
组件定义。
path
属性也可以使用相对路径(不以/
开头),匹配时就会相对于父组件的路径,可以参考上一节的例子。嵌套路由如果想摆脱这个规则,可以使用绝对路由。
path
属性可以使用通配符。
histroy 属性
Router
组件的history
属性,用来监听浏览器地址栏的变化,并将URL解析成一个地址对象,供 React Router 匹配。
history
属性,一共可以设置三种值。
- browserHistory
- hashHistory
- createMemoryHistory
如果设为hashHistory
,路由将通过URL的hash部分(#
)切换,URL的形式类似example.com/#/some/path
。
import { hashHistory } from 'react-router' render( <Router history={hashHistory} routes={routes} />, document.getElementById('app') )
如果设为browserHistory
,浏览器的路由就不再通过Hash
完成了,而显示正常的路径example.com/some/path
,背后调用的是浏览器的History API。
import { browserHistory } from 'react-router' render( <Router history={browserHistory} routes={routes} />, document.getElementById('app') )
但是,这种情况需要对服务器改造。否则用户直接向服务器请求某个子路由,会显示网页找不到的404错误。
如果开发服务器使用的是webpack-dev-server
,加上--history-api-fallback
参数就可以了。
$ webpack-dev-server --inline --content-base . --history-api-fallback
createMemoryHistory
主要用于服务器渲染。它创建一个内存中的history
对象,不与浏览器URL互动。
const history = createMemoryHistory(location)
十一、表单处理
Link
组件用于正常的用户点击跳转,但是有时还需要表单跳转、点击按钮跳转等操作。这些情况怎么跟React Router对接呢?
下面是一个表单。
<form onSubmit={this.handleSubmit}> <input type="text" placeholder="userName"/> <input type="text" placeholder="repo"/> <button type="submit">Go</button> </form>
第一种方法是使用browserHistory.push
import { browserHistory } from 'react-router' // ... handleSubmit(event) { event.preventDefault() const userName = event.target.elements[0].value const repo = event.target.elements[1].value const path = `/repos/${userName}/${repo}` browserHistory.push(path) },
第二种方法是使用context
对象。
export default React.createClass({ // ask for `router` from context contextTypes: { router: React.PropTypes.object }, handleSubmit(event) { // ... this.context.router.push(path) }, })
十二、路由的钩子
每个路由都有Enter
和Leave
钩子,用户进入或离开该路由时触发。
<Route path="about" component={About} /> <Route path="inbox" component={Inbox}> <Redirect from="messages/:id" to="/messages/:id" /> </Route>
上面的代码中,如果用户离开/messages/:id
,进入/about
时,会依次触发以下的钩子。
/messages/:id
的onLeave
/inbox
的onLeave
/about
的onEnter
下面是一个例子,使用onEnter
钩子替代<Redirect>
组件。
<Route path="inbox" component={Inbox}> <Route path="messages/:id" onEnter={ ({params}, replace) => replace(`/messages/${params.id}`) } /> </Route>
onEnter
钩子还可以用来做认证。
const requireAuth = (nextState, replace) => { if (!auth.isAdmin()) { // Redirect to Home page if not an Admin replace({ pathname: '/' }) } } export const AdminRoutes = () => { return ( <Route path="/admin" component={Admin} onEnter={requireAuth} /> ) }
下面是一个高级应用,当用户离开一个路径的时候,跳出一个提示框,要求用户确认是否离开。
const Home = withRouter( React.createClass({ componentDidMount() { this.props.router.setRouteLeaveHook( this.props.route, this.routerWillLeave ) }, routerWillLeave(nextLocation) { // 返回 false 会继续停留当前页面, // 否则,返回一个字符串,会显示给用户,让其自己决定 if (!this.state.isSaved) return '确认要离开?'; }, }) )
上面代码中,setRouteLeaveHook
方法为Leave
钩子指定routerWillLeave
函数。该方法如果返回false
,将阻止路由的切换,否则就返回一个字符串,提示用户决定是否要切换。
果开发服务器使用的是webpack-dev-server
,加上--history-api-fallback
参数就可以了。
$ webpack-dev-server --inline --content-base . --history-api-fallback
createMemoryHistory
主要用于服务器渲染。它创建一个内存中的history
对象,不与浏览器URL互动。
const history = createMemoryHistory(location)