咱之前有记录过关于redux的东西。然而就算加上了redux,react依然不能作为一个完整框架使用(其实人家本就只算是个lib…)是残缺的(对于这点我只能说,还是angular方便- -)。非常需要解决的有两点。
1、SPA得要有前端路由..。
2、网络请求放在哪里?(这一点其实官网上面有提过componentDidMount是发送网络请求的好地方原话:this is a good place to instantiate the network request.,然而在componentDidMount里面网络请求一点都不好用..原因是在componentDidMount里面延迟setState会有警告具体参考另外一篇记录,而且网络请求堆在component里面也是非常的不方便,最好能够将网络请求统一管理起来…..)
1 thunk
先来回顾一下redux流程..
在这里咱就发现了,redux有点问题,它只能dispatch一个包含了更新state数据的纯object,它没有办法再dispatch里面处理一些异步逻辑。最简单来讲我希望我发出网络请求的时候有个state更新,在请求失败的时候有个state更新,在请求成功之后有个state更新。
redux-thunk解决的就是这么一个问题,redux-thunk作为redux的中间件,在action执行之前,会判断传入的action是不是function如果是则将dispatch getState传入该function并执行。代码就几行来着..
1 | function createThunkMiddleware(extraArgument) { |
所以有了thunk之后我们写异步请求的时候就是这样写的..
1 | // eslint-disable-next-line no-unused-vars |
这里这个fetchUsers返回的是一个function,然后thunk将其拦截下来,将dispatch传入并执行这个function。
网络请求的问题解决了,那单页面应用的路由问题咋整呢?我自己在网上找的时候一片片的全是react-router。然而react-router所有的路由跳转都自己包装了一遍,我需要从react-router-dom里面引用组件来跳转。如果我想在redux的action里面进行路由跳转…又是只能挠挠头了….
2 middleWare的应用
到了项目上面发现居然用的不是这个…咱可以不用react-router-dom,所有的路由跳转都是一句话history.push()。说实话这个看上去比react-router好使多了,咱终于是能在redux里面跳转路由了。
那么这东西咋用呢,其实这个在react-router的doc里面有提及过…在https://reacttraining.com/react-router/web/guides/redux-integration的东西(翻墙体验更加),也没啥好说的看看文档就会了。主要还是想说一下项目里面别人搞得一个middleWare。
是这样的,现在做的东西虽然流程上面有点复杂,但是总体上来说是类似于银行自助服务机上面的那样的东西,就是走流程性的东西。本来以我自己的做法的话可能就是在页面上面的next button里面判断一下条件决定后面应该进入哪个页面,然后再调用history push去跳转页面。
但是这样会有个问题大量的判断逻辑堆在了component里面。会显得组件非常的臃肿,代码可能就长成这样
1 | handleNext(){ |
但是我也不知道该咋改啊….然后我没纠结多久,有人写了个middleWare去解决(虽然后面这个东西越写越臃肿..但是思路确实是学到了)…
首先,我们先收集到所有情况的路由跳转。然后根据这个建立一个url跳转的map。类似于这样的object
1 | const urlMaps = [ |
然后再暴露出一个专门控制路由的方法来。根据当前的路由(由于用的是connected-react-router,reducer里面有保存当前页面的路由的,在 state.router.location.pathname里面。
获得urlMap,然后根据urlMap中的condition来决定下一个页面的路由。
路由控制是给它整一块儿了,顺手把一些进入页面就需要干的事情给他干了,比如我每个页面的每一次进入都需要向后台发一次请求,记录页面的进入(后台需要统计每个页面的进入次数用于分析),其实也类似于打log的存在了。
这个时候咱整一个middleWare来拦截路由变化(connected-react-router每次路由变化的时候都会dispatch一个type为Location_change的action,拦截这个action即可)。
1 | export const logMiddleWare = store => next => action => { |
emmm项目上用到的redux基本上就这样了…该记录的都记录下来了。其实一开始思路想到建立一个urlMap的时候会想到一旦页面多起来了咋整。但是现在的项目是这样的,每一个flow都是一个单独的SPA,所有的状态都是单独管理互不干扰的,就算我有好几页,一页六七个flow,我也只需要专心眼前的flow就完事儿了。