过去,路由是服务端专有的部分。自从富客户端应用越来越广泛的出现在web上,我们已经不能忽视前后端之间发生巨大的变化。
在React生态环境中,React Router是公认最优秀的路由解决方案。我们可以通过Router,Route这两个标签以及一系列属性定义整个React应用的路由方案。
然而在Redux应用中,我们遇到了一些新的问题。其中一个就是,应用程序的所有状态都应该保存在一个单一的store中,而当前路由的状态很明显也应该属于应用状态的一部分。如果直接使用React Router,就意味着所有路由相关的信息脱离了Redux store的控制。这样就违背了Redux的设计思想,也给应用带来了更多的不确定性。
所以我们需要这样的一个路由系统,它既能利用React Router的声明式特性,又能将路由信息整合进Redux store中。
React Router
路由的基本原理
路由的基本原理就是保证View和URL同步,而View可以看成是资源的一种表现。当用户在Web界面中进行操作时,应用会在若干个交互状态中切换,路由则会记录下某些比较重要的状态。
这些变化同样会被记录在浏览器的历史中,用户可以通过浏览器的前进后退切换状态,同样可以将URL分享给好友。简单的说,用户可以通过手动输入或与页面交互来改变URL,然后通过同步或异步的方式向服务端发送请求获取资源,重新绘制UI。
React Router的特性
在React中,组件就是一个方法。props作为方法的参数,当它们发生变化的时候,会触发方法执行,进而帮助我们重新绘制View。在React Router中,我们同样可以把Router组件看成是一个方法,location作为参数,返回的结果同样是View。
声明式的路由
例子:
import { Router, Route, browserHistory } from 'react-router';
const routes = (
<Router history={browserHistory}>
<Route path="/" component={App} /> </Router>
);
当前页面URL为 / 时,React Router会帮我们渲染App这个组件。
当然,这只是最简单的路由情况,实际的应用中的路由配置会比这个复杂很多。由于声明式标签原生的表述能力,我们依然能够在最短的时间内对整个应用的路由设计有一个全面的了解。
嵌套路由以及路径匹配
import { Router, Route, IndexRoute, browserHistory } from 'react-router';
const routes = (
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute component={MailList} />
<Route path="/mail/:mailId" component={Mail} />
</Route>
</Router>
);
支持多种路径切换方式
React Router提供了两种解决方案供你根据自己的业务需求进行挑选。
browserHistory及history.pushstate的实现,假如想用hashChange的方式改变路由,从React Router中使用import hashHistory即可。
React Router Redux
引入React Router Redux的原因:路由状态也是应用状态的一部分。在很多情况下, 我们的业务逻辑和路由状态有很强的关联关系。
因此,当我们采用Redux架构时,所有的应用状态必须放在一个单一的store中管理,路由状态也不例外。这就是React Router Redux为我们实现的主要功能。
将React Router和Redux store绑定
React Router Redux提供了简单直白的API——syncHistoryWithStore来完成与Redux store的绑定工作。
import { browserHistory } from 'react-router'
import { syncHistoryWithStore } from 'react-router-redux'
import reducers from '<project-path>/reducers'
const store = createStore(reducers);
const history = syncHistoryWithStore(browserHistory, store);
将这个history独享传给React Router中的Router组件作为props,就给React Router Redux提供了观察路由变化并改变store的能力。
用Redux的方式改变路由
如果要改变数据,必须分发一个action。在Redux应用中要改变路由,必须分发一个action。
但是在这之前,我们需要对Redux的store进行一些增强,以便分发的action能够被正确识别。
import { browserHistory } from 'react-router';
import { routerMiddleware } from 'react-router-redux';
const middleware = routerMiddleware(browserHistory);
const store = createStore(
reducers,
applyMiddleware(middleware)
);
我们引入了routerMiddleware,它实际上是一个middleware工厂,传入history对象,返回一个真正的Redux middleware。最终,在创建Redux store时,我们将这个middleware启动,并作为参数传入createStore方法,获得被React Router Redux加工过新的store。
最后,就可以用store.dispatch来分发一个路由变动的action了:
import { push } from 'react-router-redux';
store.dispatch(push('/home'));