react-router v3学习整理
简介React Router是一个基于 React 之上的强大路由库,它可以让你向应用中快速地添加视图和数据流,同时保持页面与URL间的同步。在没有react-router的时候,我们需要对URL进行监听,当URL的hash部分(指的是 # 后的部分)变化后,根据hash来渲染不同的组件。看起来很直接,但它很快就会变得复杂起来,当我们的组件嵌套层级增加的时候,为了让我们的URL解析变得更智能,我们需要编写很多代码来实现指定URL应该渲染哪一个嵌套的UI组件分支,所以我们需要另外一个解决方案,这个时候react-router出现了。 路由配置基本使用路由配置是一组指令,用来告诉 router 如何匹配 URL以及匹配后如何执行代码。我们来通过一个简单的例子解释一下如何编写路由配置。 import React from 'react' import { Router,Route,Link } from 'react-router' const App = React.createClass({ render() { return ( <div> <h1>App</h1> <ul> <li><Link to="/about">About</Link></li> <li><Link to="/inbox">Inbox</Link></li> </ul> {this.props.children} </div> ) } }) const About = React.createClass({ render() { return <h3>About</h3> } }) const Inbox = React.createClass({ render() { return ( <div> <h2>Inbox</h2> {this.props.children || "Welcome to your Inbox"} </div> ) } }) const Message = React.createClass({ render() { return <h3>Message {this.props.params.id}</h3> } }) React.render(( <Router> <Route path="/" component={App}> <Route path="about" component={About} /> <Route path="inbox" component={Inbox}> <Route path="messages/:id" component={Message} /> </Route> </Route> </Router> ),document.body) 通过上面的配置,这个应用知道如何渲染下面四个 URL:
如果我们可以将 React.render(( <Router> <Route path="/" component={App}> <IndexRoute component={Dashboard} /> <Route path="about" component={About} /> <Route path="inbox" component={Inbox}> {/* 使用 /messages/:id 替换 messages/:id */} <Route path="/messages/:id" component={Message} /> </Route> </Route> </Router> ),document.body) 在多层嵌套路由中使用绝对路径的能力让我们对 URL 拥有绝对的掌控。我们无需在 URL 中添加更多的层级,从而可以使用更简洁的 URL。
参数获取在Message组件中,我们可以通过以下方式获取路由参数中的id const Message = React.createClass({ render(){ // 只适用于 /message/:id 形式的路由参数 // 若要获取 ?id=yourId 形式的参数,使用this.props.location.query const { id } = this.props.params; return <div>参数id:{id}</div> } }) 进入和离开的HookRoute 可以定义 onEnter 和 onLeave 两个 hook ,这些hook会在页面跳转确认时触发一次。这些 hook 对于一些情况非常的有用,例如权限验证或者在路由跳转前将一些数据持久化保存起来。 在路由跳转过程中,onLeave hook 会在所有将离开的路由中触发,从最下层的子路由开始直到最外层父路由结束。然后onEnter hook会从最外层的父路由开始直到最下层子路由结束。 继续我们上面的例子,如果一个用户点击链接,从
替换的配置方式因为 route 一般被嵌套使用,所以使用 JSX 这种天然具有简洁嵌套型语法的结构来描述它们的关系非常方便。然而,如果你不想使用 JSX,也可以直接使用原生 route 数组对象。 上面我们讨论的路由配置可以被写成下面这个样子: const routeConfig = [ { path: '/',component: App,indexRoute: { component: Dashboard },childRoutes: [ { path: 'about',component: About },{ path: 'inbox',component: Inbox,childRoutes: [ { path: '/messages/:id',component: Message },{ path: 'messages/:id',onEnter: function (nextState,replaceState) { replaceState(null,'/messages/' + nextState.params.id) } } ] } ] } ] React.render(<Router routes={routeConfig} />,document.body) 路由匹配原理路由拥有三个属性来决定是否“匹配“一个 URL:
嵌套关系React Router 使用路由嵌套的概念来让你定义 view 的嵌套集合,当一个给定的 URL 被调用时,整个集合中(命中的部分)都会被渲染。嵌套路由被描述成一种树形结构。React Router 会深度优先遍历整个路由配置来寻找一个与给定的 URL 相匹配的路由。 路径语法路由路径是匹配一个(或一部分)URL 的 一个字符串模式。大部分的路由路径都可以直接按照字面量理解,除了以下几个特殊的符号:
<Route path="/hello/:name"> // 匹配 /hello/michael 和 /hello/ryan <Route path="/hello(/:name)"> // 匹配 /hello,/hello/michael 和 /hello/ryan <Route path="/files/*.*"> // 匹配 /files/hello.jpg 和 /files/path/to/hello.jpg 如果一个路由使用了相对路径,那么完整的路径将由它的所有祖先节点的路径和自身指定的相对路径拼接而成。使用绝对路径可以使路由匹配行为忽略嵌套关系。 优先级最后,路由算法会根据定义的顺序自顶向下匹配路由。因此,当你拥有两个兄弟路由节点配置时,你必须确认前一个路由不会匹配后一个路由中的路径。例如,千万不要这么做: <Route path="/comments" ... /> <Redirect from="/comments" ... /> HistoryReact Router 是建立在
你可以从 React Router 中引入它们: // JavaScript 模块导入(译者注:ES6 形式) import { browserHistory } from 'react-router' 然后将它们传递给 render( <Router history={browserHistory} routes={routes} />,document.getElementById('app') ) browserHistoryBrowser history 是使用 React Router 的应用推荐的 history。它使用浏览器中的 History API 用于处理 URL,创建一个像example.com/some/path这样真实的 URL 。 服务器配置服务器需要做好处理 URL 的准备。处理应用启动最初的 const express = require('express') const path = require('path') const port = process.env.PORT || 8080 const app = express() // 通常用于加载静态资源 app.use(express.static(__dirname + '/public')) // 在你应用 JavaScript 文件中包含了一个 script 标签 // 的 index.html 中处理任何一个 route app.get('*',function (request,response){ response.sendFile(path.resolve(__dirname,'public','index.html')) }) app.listen(port) console.log("server started on port " + port) IE8,IE9 支持情况如果我们能使用浏览器自带的 window.history API,那么我们的特性就可以被浏览器所检测到。如果不能,那么任何调用跳转的应用就会导致 全页面刷新,它允许在构建应用和更新浏览器时会有一个更好的用户体验,但仍然支持的是旧版的。 你可能会想为什么我们不后退到 hash history,问题是这些 URL 是不确定的。如果一个访客在 hash history 和 browser history 上共享一个 URL,然后他们也共享同一个后退功能,最后我们会以产生笛卡尔积数量级的、无限多的 URL 而崩溃。 hashHistoryHash history 使用 URL 中的 hash(#)部分去创建形如 我应该使用
|