【React系列】从零开始入门Redux

       我在学习redux的时候,一开始也以为很难,不少东西很难以理解,由于我是先简单学习了一遍Vue的,由于工做中用的都是react,因此Vue也忘得差很少了。写这篇文章的缘由是想帮助想入门react的小伙伴们,同时也是对本身的一个技术小总结吧。前端

       react难就难在它很自由,就提供了一个JSX,而后就没有了。不过和当初React的定位也有关系,它并非一个框架,而是一个UI库。而Vue才是一个框架,由于不少事情它都帮你完成了,使用的时候仅须要知道相关的API。react

       tips:能够这么粗浅的理解react,UI = fn(data)git

好了扯远了,下面开始带你入门redux吧。github

redux

       首先,在学习以前,要说明一点,react和redux没有任何关系,没有任何关系,没有任何关系;重要的事情说三遍。那redux是什么呢?是一个管理数据的仓库。编程

为何须要redux呢?

      缘由是由于前端数据的复杂度没有人来管理,由于react当初的定位也是为了解决中大型项目,项目一旦复杂起来,须要共享的数据就会很庞大复杂。redux

redux的核心概念

      在介绍核心概念以前,咱们先来了解一个东西,就是Flux。在Flux中,Facebook最先提出了一个action的概念,经过action来直接修改数据仓库store,action是一个普通的对象,用于描述要干什么。store根据不一样的action来对数据进行操做。数组

      这样就会有一个问题,当业务复杂,数据庞大的时候,store的压力就不少了,因此才有了后面redux的出现,到这里,你只须要知道redux的三个核心概念就能够了。app

      action:至关于页面请求等操做,分发dispatch框架

      reducer:数据的控制器,数据的修改者,就是修改数据的

      store:数据的仓库函数式编程

redux是如何工做的?


第一步:首先action是一个平面对象,就是一个简单的对象,必需要传type属性,类型任意,表明着你要干什么,还有一个可选属性是payload,就是请求时候的附加数据。

第二步:store接收到action的请求以后,把旧的数据state,和请求action交给reducer,让reducer来修改数据,修改完以后返回一个新的数据newState给我,以便更新数据。

       明白了上图描述的redux工做流程以后,咱们须要建立一个store,由于根据上图,不论是接收action,或者是触发reducer修改数据,都是根据数据仓库的,全部咱们先要建立一个数据仓库。直接看下面代码和注释吧。

createStore

       createStore 返回值是一个对象,对象包含如下几个属性

       dispatch:分发一个action,天然要接收一个action参数

       getState:获得当前的state数据

       subscribe:订阅一个监听器,分发action的时候自动会执行,订阅时候返回一个函数,方便取消订阅。

       Symbol('observable'):提案,暂时用不到

tips:到这里,熟悉发布订阅模式的小伙伴,就知道其实 createStore 内部的代码原理就是使用了发布订阅模式。不熟悉发布订阅模式的小伙伴须要去了解一下。

代码


接着咱们把action和reducer完善好


最后咱们就可使用了,结合上图的两个步骤理解


tips:最好本身手动实现一遍代码,而后按照redux工做原理两大步骤图理解一下。

bindActionCreators

       根据上面redux的工做流程,有没有发现太麻烦了?的确是太麻烦了,尤为是第二步,要本身主动去使用store.dispatch,而后再往里面塞action的平面对象。那有没有方便一点的方法呢?redux提供了一个函数,bindActionCreators,加强action建立函数,让action以后自动触发dispatch。

/**
* bindActionCreators,加强action,自动dispach。
* 接受两个参数
* 第一个是actions,若是是函数,返回一个函数,若是是对象,返回一个对象
* 第二个dispach,actions须要加强的函数
*/

代码


使用起来就至关简单了,下面作一个对比


combineReducers

       如今还有一个问题,就是仓库数据只有一个,只有一个reducer,而在实际的项目中,数据是很庞大的,有不少个reducer,那怎么来管理这么多数据呢?


代码

咱们能够先这样解决问题


其实redux很贴心,为我么提供了至关于上面效果的一个函数,就是 combineReducers。

/**
* 组装reducers, 返回一个reducer,数据使用一个对象表示,
* 对象的属性名与传递的参数对象保持一致
* 返回的是一个总的 reducer函数
*/


完善 validiteReducers 函数


使用的时候,只须要简单的导出 combineReducers 的运行结果便可,由于它返回一个总的reducer函数,能够对比一下不使用combineReducers的时候。


middleware

       如今咱们基本上算是完成了一个简陋版的redux,可是在实际的业务开发中,每每须要请求数据,打印日志之类的不少附加功能,咱们就举一个简单的例子。如今有一个需求,我要打印旧数据和新数据。首先咱们分析一下需求,结合redux的工做流程,咱们知道,action必须返回一个没有反作用的平面对象,reducer必须是一个纯函数。何况action只能拿到旧数据,reducer也不行,观察发现createStore里面的能够拿,那只能在里面作手脚了。怎么作手脚呢?又不能影响原来的功能。

代码

机智的咱们能够先这样作


其实这个就是middleware中间件的原理。并且,中间件如何运用在redux上?总不能像上面这么low的写法吧?别急,咱们一步步慢慢分析,理清楚下面这些概念

/**
* 什么是中间件?
* 中间件,像插件,能够不影响本来功能、而且不改动本来代码的基础上,对其功能进行加强。
* 在redux中,主要是加强dispatch函数
*
* 原理:更改仓库中的dispatch函数
* 1.先用一个变量保存原来的引用,而后彻底改写了原来的函数。
* 2.在新改写的函数中加强咱们须要的功能以后再运行一下原来的函数。
* 3.这样就达到了目的了
*
* 如何书写?
* 1.中间件自己是一个函数,该函数接受一个store参数,表示建立的仓库
* 2.该仓库并不是一个完成的仓库,仅包含getState, dispatch
* 3.该函数等仓库建立完运行
* 4.因为建立仓库后须要自动运行设置的中间件函数,所以须要在建立仓库时,告诉仓库有哪些*    中间件
* 5.须要调用applyMiddleware函数,将函数的返回值做为createStore的第二或第三参数
*
* 6.中间件函数必须返回一个函数,用来建立dispatch函数
*/

先看第五点,要使用中间件,必须调用applyMiddleware函数,将函数的返回值做为createStore的第二或第三参数,来告诉仓库,咱们建立仓库的时候,要使用中间件。假设咱们有下面三个中间件,建立仓库的时候调用applyMiddleware函数。applyMiddleware函数会倒着来运行每一个中间件。在这里你能够先无论它为何倒着来,先忽略。


而后用代码来写一遍,先书写三个中间件。


而后使用中间件


applyMiddleware

到这里,你可能会问applyMiddleware为何要倒着来运行全部的中间件,这和代码的运行逻辑有关,下面咱们就来解析一下applyMiddleware是怎么来把全部的中间件运行起来的。在介绍applyMiddleware前,咱们先来认识一下compose,它是函数组合, 函数式编程中的声明式编程,其实就是把全部的函数的功能组合到一块儿。

compose

其实能够简单的理解成,把全部函数的功能组合成一个函数,就是compose。


有了compose以后,咱们就能够实现applyMiddleware的原理了,以下代码


到这里,咱们就知道为何applyMiddleware一开始调用的时候是反过来的了。compose函数式编程的魔法,真香!!!

/**
* 为何applyMiddleware一开始调用的时候是反过来的呢?
* 由于applyMiddleware以后,dispatch才会运行,这时候才是正向运行,
* 若是一开始不倒着来,获得的结果是倒着的喔!!!
* 在中间件中,若是不调用next,就不会调用下一个中间件。
* 这样的好处就是本身完成本身的事件了,无论你有几个中间件。
*/

至此,三个中间件就会运用在建立函数里面了,这也是为何建立函数的第二个参数能够传中间件或者默认值,createStore的完整代码应该是这样的。

只看上面的代码确定很羞涩难懂,结合下面的图片看才好理解


其实redux用applyMiddleware使用中间件就是一个洋葱模型,用到切洋葱(redux)的时候真想哭(学redux),吃洋葱(react+redux)的时候,真香。


redux-thunk【扩展】

咱们在写业务代码的时候,经常须要AJAX请求数据回来才渲染界面, 若是用redux请求数据,我又坚持要放在action呢?该怎么请求呢?咱们知道,action必须返回一个没有反作用的平面对象,不行,怎么办呢? redux-thunk 中间件就是专门处理带有反作用的action的

/**

* redux-thunk 中间件,处理反作用, 通常放在第一个。(后面解释)
* 怎么处理反作用呢?他是处理action的反作用的。
* action 必须是一个平面的对象,没有任何的反作用,可是有了thunk以后,
* 它可让 action 变成一个函数,容许有反作用。当 action 是一个函数被分发时,
* thunk 会阻止 action 继续向后移交。要继续dispatch才日后移交,
* 这样的话就能够在里面处理不少反作用了,好比AJAX请求等等。
* thunk会向函数中传三个参数:
* dispatch:store.dispatch (为了从新走一次流程)
* getState: store.dispatch (能够获取数据)
* extra:用户设置的额外参数 thunk.withExtraArgument(123), 使用中间件的时候配置下去。
*/

代码


那为何要放在第一个呢?


tips:再仔细想下整个流程,最后跟着思路码一边。

thunk源码


connect

前面咱们都是在讲redux怎么管理数据,那咱们的组件怎么使用数据呢?

假设咱们都定义好了action、reducer,而且建立好了store。

那么接下来咱们能够这样拿到数据(Users组件拿),直接定义两个方法,把须要的数据映射进去。


仔细看mapStateToPropsmapDispatchToProps。咱们把须要的数据直接经过导入store,传进去就完事了。同时订阅一下this.setState就能够完成改变数据就刷新界面的效果。

redux仍是很贴心的,哪里麻烦就出哪里的API,这时候就可使用react-redux中的 connect 方法了。首先你要理解下面的笔记,或者能够直接去看相关的API文档。


有了connect以后代码就能够变得很简单了。直接导出就完事了


总结

       redux其实使用不难,可是理解原理,解析原理代码是很是绕的,必定要多写几遍代码理解才能真的学会使用redux。

       这里提供我学习redux源码的全部代码笔记,有兴趣的小伙伴能够clone下来研究学习。

github:github.com/huangruitia…

相关文章
相关标签/搜索