序
现在用react写单页应用基本上都是用react-router做前端路由了吧!最近在使用react-router的过程中遇到了不少问题,在这里总结一下。
浏览器url
react-router默认提供的history是 createHashHistory ,即它用到的是 URL 中的 hash(#
)部分去创建形如 example.com/#/some/path
的路由,所以你会看到url多了类似 _key=s1gvrm 的 query,这真的很难看。而且这也不是官方在实际生产应用中所推荐的。要改变这种情况的话,我们需要去使用 createBrowserHistory ,在我们的代码中引入history,并在Router组件处调用
createBrowserHistory
方法即可。
import React from "react"; import ReactDOM from "react-dom"; import createBrowserHistory from "history/lib/createBrowserHistory" import { Router,Route,Link,browserHistory,IndexRoute,IndexLink } from "react-router"; class App extends React.Component{ render(){ return( ... ); } }; ReactDOM.render(( <Router history={ createBrowserHistory() }> ... </Router> ),document.getElementById("app"));
其实关于url还有许多的细节,因为react-router本身就是构建于history之上的。单页应用的url只不过是针对于react-router的一个标示而已,界面间的跳转全然由react-router决定,react-router检查当前url随后渲染匹配的路由组件,所以在浏览器上直接输入一个正确的非根路径你甚至只能看到404。
组件通信
这是一个用react写代码永远都绕不开的话题。react-router是基于react开发的,所以它的每一个route都是一个组件。路由组件间的通信一般借由Link来实现,而根据路由参数的不同,还可以分成两种。这个很容易理解,因为这两种方式和我们平时写的后台路由并没有什么太大差别。
1 param,param通过/:param的方式传递。
比如说我们现在有一个显示消息列表的路由组件,我们需要在点击每一个消息的时候能跳转到显示被点击消息详情的路由组件。这个时候我们消息详情路由组件可以是这样定义的:
<Route path="News_detail/:news_id" component={ news_detail }/>
在消息列表路由组件那里我们让每一条消息都是这样的一个Link:
<Link to={ `News_detail/${ element.timestamp }` } >{ element.news }</Link>
这样的话我们的消息详情组件就能通过 this.props.params 获取到消息列表组件传递而来的 element.timestamp 参数了。
2 query
<Link to="/Activity_Publish" query={{ timestamp : element.timestamp }}>编辑</Link>
在 /Activity_Publish 映射的路由组件里面可以通过
var { query } = this.props.location; var timestamp = query.timestamp;
获取到query参数。
相对于param,局限性更小,你可以根据需要传递更多的参数,只不过有点类似于get请求,传递的参数会附带在url后面,看起来有点丑,而且几乎无隐蔽性可言。
3 state
不过还是有第三种方式的,就是state,这种方式借助了location 对象,
location 对象
可以简单的认为是 url 的对象形式表示,这里要提的是 location.state
,每个 URL 都会对应一个 state 对象,你可以在对象里存储数据,但这个数据却不会出现在 url 中。实际上,数据被存在了 sessionStorage 中,所以这种方式简直就是query的加强版。
<Link to="/Activity_Publish" state={{ timestamp : element.timestamp }}>编辑</Link>
按需加载
react-router协同webpack的使用可以实现组件的按需加载,而且这种按需加载完全是异步的,这点特别酷炫,你不再需要一口气加载那么大的js文件,即使里面包含着许多用户甚至都不会使用到的web组件。你可以只根据需要加载用户浏览的那些组件,这个举措将会帮你大大的降低首屏渲染的时间。
实现这个功能很简单,比如在一开始你的路由是这样子的:
... import News_detail from "./marriage_component/activity/news_detail.jsx"; ... class App extends React.Component{ render(){ ... } }; ReactDOM.render(( <Router history={ createBrowserHistory() }> <Route path="/marriage_app" component={ App }> ... <Route path="/marriage_app/News_detail/:news_id" component={ News_detail }/> ...
把它改成这样就行了:
... //import News_detail from "./marriage_component/activity/news_detail.jsx"; ... class App extends React.Component{ render(){ ... } }; ReactDOM.render(( <Router history={ createBrowserHistory() }> <Route path="/marriage_app" component={ App }> ... <Route path="/marriage_app/News_detail/:news_id" getComponent={ (nextState, callback) =>{ require.ensure( [ ], (require) => { callback(null, require("./marriage_component/activity/news_detail").default) }) } }/> ...
一开始的组件不再需要被导入,webpack会帮你在需要的时候引入它。
最后
这种前后端分离的模式让我们团队的后台特别开心,不过其实他不知道,这种前端掌控一切的感觉也让我很得意啊哈哈,以后谁再说我切图仔我跟谁急。