谁都能听懂的Redux+Redux-Saga超级傻瓜教程
对不起本文确实有标题党的嫌疑:) 想要理解本文还是要先会用react和es6,如果连react和es6都不知道是什么的话我也没辙:(
如果你选择用react来开发应用,并且你没对各个组件的状态进行应有的管理,那么当应用变得庞大的时候你会发现组件之间的通信变得错综复杂,各个组件之间的数据传递往往会乱成一团,从而导致加班、延期、炒鱿鱼等不好的事情:( 这个时候就需要引入“状态管理”这个概念来挽救一团乱麻的代码。状态管理,就是将各个组件之间相互独立的状态和数据给统一的管控起来,让原本错综复杂的数据流向变成单向,这样状态就变得容易管理和理解,从而让程序变得易于维护。
今天我们讲的就是react目前最流行的状态管理工具redux和它的一些周边组件。废话不多说,我们先准备好react开发环境,打开ide开始敲代码。
环境这块我就不讲了,最基础的webpack+react即可。
首先先安装redux(yarn add redux -S),清空src目录,新建一个入口js文件(index.js),输入以下内容:
import { createStore } from 'redux' const reducer = function (state, action) { console.log(action.type) return state } const store = createStore(reducer) store.dispatch({type: 'hello'})
然后启动dev server,打开浏览器和控制台,就可以看到输出了“hello”。现在来稍微解释下这段代码:
createStore,从字面上理解,就是创建仓储,这个仓储用来存放数据和修改数据的方法。
dispatch,直译过来是指派、调度,可以理解成命令store执行修改数据的操作。传入一个对象来描述要执行的动作。我们称这个对象为action。
reducer,直译过来是还原剂,这里就把它理解成存放数据和修改数据的方法的地方。如果把store比喻成仓库,那么reducer就是用来装载货物的集装箱。reducer接受的第一个参数是数据,第二个参数用来描述动作,里面是dispatch过来的对象和数据,我们可以利用type属性结合switch case语句来进行具体的状态修改。还有要记得返回state,如果没有返回state就会报错。
我们把reducer扔到createStore这个函数里,就返回了一个store。然后再调一下store里面的dispatch方法,就执行了一次reducer。这样一个最简单的redux管理状态的流程就跑完了。
在这个例子里我们只使用了一个reducer,而一个reducer只有一个state,但是我们的应用肯定不止一个组件,这个时候就需要多个reducer。
为了将多个reducer组合起来,我们又要引入一个redux里的函数,叫combineReducers。
import {combineReducers, createStore} from 'redux' const list = function (state = [], action) { //state=[]表示的是state的初始状态 console.log(action.type) console.log('list') return state } const counter = function (state = 0, action) { console.log(action.type) console.log('counter') return state } const reducers = combineReducers({ list, counter }) const store = createStore(reducers) store.dispatch({type: 'hello'})
这样就将多个reducer组合起来了。调用dispatch的时候所有reducer都会被执行。
到了这里我们就已经可以进行一些简单的本地状态管理了。但是几乎所有的应用都有涉及到ajax异步请求,这些代码要放到哪里呢?如果放到reducer里的话由于reducer要求立即返回state,不然报错。解决方案是有的,不过有些繁琐,可以参考阮一峰老师的教程:
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.html
如果没看懂的话也没关系,如果你能够在项目中运用redux-saga的话,就可以很轻松的解决异步问题了:)
我们先认真的把redux-saga官方提供的案例给看一看
https://redux-saga-in-chinese.js.org/docs/introduction/BeginnerTutorial.html
redux-saga的使用很简单,和之前redux的做法差不多。先定义saga(也称为effect。类似reducer,不过可以调用异步方法,不能修改状态),然后在顶层(index.js)注册之前写好的saga即可。
在saga(effect)中,我们可以通过takeEvery来监听dispatch,通过call来调用异步方法,通过put来触发reducer,通过select来获取状态。要注意的是saga都是Generator函数(带*号),也只有Generator函数里才能调用yield。这样异步问题就差不多解决了。
说了这么多,总得应用到react里面去吧。react里的各个组件想要获取到store里的状态和命令store进行数据修改,如果不安装其他包的话就只能在根级组件把store一级一级的传递下去,中间有一级没传递store那么之后的组件就全部无法使用redux进行状态管理了,这样显然是有待改进的。所以我们还要再装一个包:react-redux。
React-redux核心的方法只有两个:Provider和connect。Provider用来包裹根级组件,并接收store,connect用来将组件的props与store连接起来,这样即使不一层层的传递store每个组件也可以接收到store。
export default connect((state) => { return {list: state.userList.list} // 将store与组件连接起来。connect第一个参数是一个函数,要求返回用来描述props和store的对象。 })(List)
这样我们基本上就能把redux给实际的应用起来了,但是还有一个问题值得我们思考:store调用dispatch后所有的reducer都会被执行,而每个reducer里面只能用switch case之类的流程控制语句来指定执行哪个reducer,如果项目一大,各个方法的命名岂不是很容易混乱?别着急,这个时候需要本文要谈到的最后一个包:dvajs。dvajs将一组数据和相应的修改数据的方法包装成一个module,组件调用dispatch的时候可以通过指定type属性来直接调用相应module的effect或者reducer。dvajs的具体使用除了参考官网的案例以外,还可以参照这篇博文:https://www.cnblogs.com/axel10/p/8503782.html。只要你能够从redux->redux-saga->react-redux这个流程学下来,就会发现dvajs几乎没有多少新知识点,很快就能够上手。
如果觉得教程里有地方讲的不是很理解的可以将下面这个案例下载下来看一看,相信很多问题都会得到答案。
一个在线获取用户列表,点击项目可删除的例子