四、Redux的异步操作
组件中异步操作
- 在之前简单的案例中,redux中保存的counter是一个本地定义的数据
- 我们可以直接通过同步的操作来dispatch action state就会被立即更新。
- 在开发中, redux中保存的很多数据可能来自服务器,我们需要进行 异步的请求,再 将数据保存到redux中
- 在之前学习网络请求的时候我们讲过,网络请求可以在class组件的componentDidMount中发送,所以我们可以有这样的结构:
redux中异步操作
- 上图有一个缺陷:
- 我们必须 将网络请求的异步代码放到组件的生命周期中来完成
- 事实上, 网络请求到的数据也属于我们状态管理的一部分,更好的一种方式应该是 将其也交给redux来管理
但是在redux中如何可以进行异步的操作呢?
- 答案就是使用中间件 (Middleware)
- 学习过Express或Koa框架对中间件的概念一定不陌生
- 在这类框架中,Middleware可以帮助我们 在请求和响应之间嵌入一些操作的代码,比如cookie解析、日志记录、文件压缩等操作
理解中间件
- redux也引入了中间件(Middleware)的概念:
- 这个中间件的目的是 在dispatch的action和最终达到的reducer之间,扩展一些自己的代码
- 比如 日志记录、调用异步接口、添加代码调试功能等等
- 我们现在要做的事情就是发送异步的网络请求,所以我们可以添加对应的中间件:
- 这里 官网推荐的、包括演示的网络请求的中间件是 使用 redux-thunk
redux-thunk是如何做到让我们可以发送异步的请求呢
- 我们知道, 默认情况下的dispatch(action),action需要是一个JavaScript的对象
- redux-thunk可以让 dispatch(action函数),action 可以是一个函数
- 该函数会被调用,并且会传给 这个函数一个dispatch函数和getState函数
- dispatch函数用于我们之后再次派发action
- getState函数考虑到我们之后的一些操作需要依赖原来的状态,用于让我们可以获取之前的一些状态
如何使用redux-thunk
- 1.安装redux-thunk
- Npm install redux-thunk
- 2.在创建store时传入应用了middleware的enhance函数
- 通过applyMiddleware来结合多个Middleware,返回一个enhancer;
- 将enhancer作为第二个参数传入到createStore中;
- 3.定义返回一个函数的action:
- 注意:这里不是返回一个对象了,而是一个函数;
- 该函数在dispatch之后会被执行
五、redux-devtool
redux-devtools
- redux可以方便的让我们对状态进行跟踪和调试,那么如何做到呢?
- redux官网为我们 提供了redux-devtools的工具
- 利用这个工具,我们可以知道 每次状态是如何被修改的,修改前后的状态变化等等
安装该工具需要两步:
- 第一步:在对应的浏览器中安装相关的插件(比如Chrome浏览器扩展商店中搜索Redux DevTools即可);
- 第二步:在redux中继承devtools的中间件
六、reducer的模块拆分
Reducer代码拆分
- 我们先来理解一下,为什么这个函数叫reducer?
- 我们来看一下目前我们的reducer:
- 当前这个reducer既有处理counter的代码,又有处理home页面的数据
- 后续counter相关的状态或home相关的状态会进一步变得更加复杂
- 我们也会继续添加其他的相关状态,比如购物车、分类、歌单等等
- 如果将所有的状态都放到一个reducer中进行管理,随着项目的日趋庞大,必然会造成代码臃肿、难以维护
- 因此,我们可以对reducer进行拆分:
- 我们先抽取一个对counter处理的reducer
- 再抽取一个对home处理的reducer
- 将它们合并起来
Reducer文件拆分
- 目前我们已经将不同的状态处理拆分到不同的reducer中,我们来思考:
- 虽然已经放到不同的函数了,但是这些函数的处理依然是在同一个文件中,代码非常的混乱
- 另外关于reducer中用到的constant、action等我们也依然是在同一个文件中
combineReducers函数
- 目前我们合并的方式是通过每次调用reducer函数自己来返回一个新的对象
- 事实上,redux给我们提供了一个combineReducers函数可以方便的让我们对多个reducer进行合并:
那么combineReducers是如何实现的呢?
- 它也是 将我们传入的reducers合并到一个对象中,最终 返回一个combination的函数(相当于我们之前的reducer函数了)
- 在 执行combination函数的过程中,它会 通过判断前后返回的数据是否相同来决定返回之前的state还是新的state
- 新的state会触发订阅者发生对应的刷新,而 旧的state可以有效的阻止订阅者发生刷新;