温习react-router
原文链接:https://react-guide.github.io... react-router是一个基于react的路由库,它可以让你向应用中快速的添加视图和数据流,同时保持页面与URL之间的同步。 路由配置1. 不使用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('hashchage',()=> { 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> ) } }) React.render(<App />,document.body) 如上,当URL的hash部分(指的是#后的部分)变化后,<App>会根据this.state.route来渲染不同的<Child>。现在看起来很直观,但是当你的路由结构复杂,项目变的比较庞大的时候,这种方法可能就不太适合了。 import React from 'react' import { render } from 'react-dom' // 首先我们需要导入一些组件... import { Router,Route,Link } from 'react-router' const App = React.createClass({ render() { return ( <div> <h1>App</h1> {/* 把 <a> 变成 <Link> */} <ul> <li><Link to="/about">About</Link></li> <li><Link to="/inbox">Inbox</Link></li> </ul> {/* 接着用 `this.props.children` 替换 `<Child>` router 会帮我们找到这个 children */} {this.props.children} </div> ) } }) // 最后,我们用一些 <Route> 来渲染 <Router>。 // 这些就是路由提供的我们想要的东西。 React.render(( <Router> <Route path="/" component={App}> <Route path="about" component={About} /> <Route path="inbox" component={Inbox} /> </Route> </Router> ),document.body) 看上面代码我们除去了对hash路由的判断,取而代之的是通过react-router控制了视图的显示。在内部,router会将你树级嵌套格式的<Route>转变成路由配置。我们也可以通过普通对象的方式来替代路由配置: const routes = { path: '/',component: App,childRoutes: [ {path: 'about',component: About},{path: 'inbox',component: Inbox} ] } React.render(<Router routes={routes}>) 2. 获取URL参数当渲染组件时,React Router会自动向Route组件中注入一些有用的信息,尤其是路径中动态部分的参数。 const Message = React.createClass({ componentDidMount() { // 来自于路径 `/inbox/messages/:id` const id = this.props.params.id fetchMessage(id,function (err,message) { this.setState({ message: message }) }) },// ... }) 3. 路由配置路由配置是一组指令,用来告诉router如何匹配URL以及匹配后如何执行代码。 import React from 'react' import { Router,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) 通过上面的配置,可以看到路由是怎么渲染的:
4. 添加首页设想一下,当url为/时,我们想渲染一个在App中组件,不过此时App的render中的this.props.children还是undefined。这种情况下,可以使用IndexRoute来设置一个默认页面。 import { IndexRoute } from 'react-router' const Dashboard = React.createClass({ render() { return <div>Welcome to the app!</div> } }) React.render(( <Router> <Route path="/" component={App}> {/* 当 url 为/时渲染 Dashboard */} <IndexRoute component={Dashboard} /> <Route path="about" component={About} /> <Route path="inbox" component={Inbox}> <Route path="messages/:id" component={Message} /> </Route> </Route> </Router> ),document.body) 此时,App的render中的this.props.children会将是<Dashboard>这个元素。
5. 让UI从URL中解耦出来如果我们可以将/inbox从/inbox/messages/:id中去除,并且能够让Message嵌套在App-Inbox。那我们可以通过绝对路径实现。 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) 绝对路径可能在动态路由中无法使用 6. 兼容旧的URL如果改为/inbox/messages/5,这样都会匹配不到路径,会返回一个错误页面,我们可以通过<Redirect>使URL重新正常工作。 import { Redirect } from 'react-router' React.render(( <Router> <Route path="/" component={App}> <IndexRoute component={Dashboard} /> <Route path="about" component={About} /> <Route path="inbox" component={Inbox}> <Route path="/messages/:id" component={Message} /> {/* 跳转 /inbox/messages/:id 到 /messages/:id */} <Redirect from="messages/:id" to="/messages/:id" /> </Route> </Route> </Router> ),document.body) 现在,当有人惦记/inbox/message/5这个链接,他们会自动跳转到/message/5。 7. 替换的配置方式因为route一般被嵌套使用,所以使用JSX这种天然具有简洁嵌套型语法的结构来描它们的关系非常方便。我们也可以使用原生route数组对象。 const routeConfig = [ { path: '/',indexRoute: { component: Dashboard },childRoutes: [ { path: 'about',{ path: 'inbox',component: Inbox,childRoutes: [ {path: '/messages/:id',component: Message },{path: 'message/:id',onEnter: function(nextState,replaceState) { replaceState(null,'/messages/' + nextState.params.id) }} ]} ] } ] 路由匹配原理路由由三个属性来决定是否匹配一个URL: 1. 嵌套关系 2. 路径语法 3. 优先级 1. 嵌套关系React Router使用路由嵌套的概念让你定义view的嵌套集合,当一个URL调用时,整个路由集合中(匹配的部分)都会被渲染。嵌套路由被描述成一种属性结构,Reat-Router会深度优先遍历整个路由配置来寻找一个给定的URL相匹配的路由。 2. 路径语法路由路径是匹配一个URL的一个字符串模式,大部分的路由路径都可以直接按照字面量理解,但是以下有几个特殊的符号: 1. :paramName -- 匹配一段位于/,?或者#之后的URL.命中的部分将被作为一个参数。 2. () -- 在它内部的内容被认为是可选的 3. * --匹配任意字符串直到命中下一个字符或者整个URL的末尾,并创建要给splat参数。 例子: <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 3. 优先级路由算法会根据定义的顺序自顶向下匹配路由,因此,当你拥有两个兄弟路由节点匹配时,你必须确认前一个路由不会匹配后一个路由中的路径。 HistoriesReact Router时建立在history上的,简而言之,一个history知道如何去监听浏览器地址的变化,并解析这个URL转为location对象,然后router使用它匹配到路由,最后正确的渲染对应组件。 1. borwserHistory 2. hashHistory 3. createMemoryHistory import {browserHistory} from 'react-router' render( <Router history={browserHistory} routes={routes} />,document.getElementById('app') ) 1. browserHistoryBrowser history 是使用 React Router 的应用推荐的 history。它使用浏览器中的 History API 用于处理 URL,创建一个像example.com/some/path这样真实的 URL 。 2. hashHistoryHash history 使用 URL 中的 hash(#)部分去创建形如 example.com/#/some/path 的路由。 默认路由(IndexRoute)与 IndexLink1. 默认路由首先,我们看下不使用默认路由的情形: <Router> <Route path="/" component={App}> <Route path="accounts" component={Accounts}/> <Route path="statements" component={Statements}/> </Route> </Router> 当用户访问/时,App组件被渲染,但组件内的子元素却没有,App内部的this.props.children为undefined。你可以简单的使用{this.props.chidlren || ''}来渲染默认组件。 <Router> <Route path="/" component={App}> <IndexRoute component={Home}/> <Route path="accounts" component={Accounts}/> <Route path="statements" component={Statements}/> </Route> </Router> 现在 App 能够渲染 {this.props.children} 了, 我们也有了一个最高层级的路由,使 Home 可以参与进来。 2. Index Links如果你在这个 app 中使用 <Link to="/">Home</Link>,它会一直处于激活状态,因为所有的 URL 的开头都是 / 。 这确实是个问题,因为我们仅仅希望在 Home 被渲染后,激活并链接到它。 如果需要在 Home 路由被渲染后才激活的指向 / 的链接,请使用 <IndexLink to="/">Home</IndexLink> 动态路由对于大型应用来说,一个首当其冲的问题就是所需加载的 JavaScript 的大小。程序应当只加载当前渲染页所需的 JavaScript。有些开发者将这种方式称之为“代码分拆” —— 将所有的代码分拆成多个小包,在用户浏览过程中按需加载。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |