Redux(1)

来源:互联网 发布:大二申请国外大学知乎 编辑:程序博客网 时间:2024/06/05 10:23

Redux简介

这里写图片描述

Redux的核心代码可以理解成一个库,但同时也强调了一种架构思想。

上面这个图是Redux的核心运作流程。

Redux本身指redux这个npm包,它提供若干API让我们使用reducer创建store,并能够更新store中的数据或获取store中最新的状态。

Redux三大原则

单一数据源

整个应用的状态都保存在一个对象中,即,一个应用永远只有唯一的数据源。

状态只读

在Redux中,我们并不会自己用代码来定义一个store。取而代之的是,我们定义一个reducer,它的功能室根据当前触发的action对当前应用的状态进行迭代。这里我们并没有直接修改应用的状态,而是返回了一个新的状态。

状态的修改必须由纯函数完成

在Redux里面,我们通过定义reducer来确定状态的修改,而每个reducer都是纯函数,这意味着它没有副作用,接受一定的输入,必定会得到一定的输出。

核心API

Redux的核心是一个store,这个store由Redux提供的createStore(reducers[, initialState])方法生成。

reducers

在Redux里,负责响应action并修改数据的角色就是reducer。它本质是一个函数,函数签名:reducer(previousState, action) => newState 。reducer的职责就是根据previousState和action计算出新的newState。

createStore

import { createStore } from 'redux';const store = createStore(reducers);

store包含4个方法。

getState():获取store中当前状态dispatch(action):分发一个action,并返回这个action。这是唯一能改变store中数据的方式subscribe(listener):注册一个监听者,在store发生变化时调用

与React绑定

react-redux提供了一个组件和一个API帮助Redux和React进行绑定,一个是React组件Provider,一个是connect。关于它们,只需要知道:Provider接受一个store作为props,它是整个Redux应用的顶层组件。而connect提供了在整个React应用的任意组件中获取store中数据的功能。

middleware

推荐一篇博客:https://segmentfault.com/a/1190000003746223#articleHeader4

可以先看这篇博客,了解middleware的机制后,再回来看源码。

在middleware中,你可以检阅每个流过的action,挑选出特定类型的action进行操作,给你一次改变action的机会。

面对多样的业务场景,单纯的修改dispatch或者reducer的代码显然不具有普适性,我们需要的是可以组合的,自由插拔的插件机制。另外,Redux中的reducer更关心的是数据的转化逻辑,所以middleware就是为了增强dispatch而出现的。

每个middleware处理一个相对独立的业务需求,通过串联middleware实现变化多样的功能。

middleware机制

Redux提供了applyMiddleware方法来加载middleware。

这里写图片描述

下面的4个部分深入解析了middleware的运行原理。

函数式编程思想设计

middleware是一个层层包裹的匿名函数,这其实是函数式编程中的currying,它是一种使用匿名单参函数来实现多参函数的方法。

currying的middleware结构的好处具有以下两点:
1、易串联:currying函数具有延迟执行的特性,通过不断currying形成的middleware可以累积参数,再配合组合的方式,很容易形成pipeline来处理数据流。
2、共享store。

给middleware分发store

let newStore = applyMiddleware(mid1, mid2, mid3, ...)(createStore)(reducer, null);

上述代码执行完成后,applyMiddleware方法陆续获得了3个参数,第一个是middleware数组,第二个是redux原生的createStore,最后一个是reducer。

之后,applyMiddleware利用createstore和reducer创建了一个store,而store的getstate方法和dispatch方法又被直接和见解的赋值给middlewareAPI变量stor:

const middlewareAPI = {    getState: store.getState,    dispatch: (action) => dispatch(action),};chain = middlewares.map(middleware => middleware(middlewareAPI));

然后,让每个middleware带着middlewareAPI这个参数分别执行一遍。执行完成后,获得chain数组[f1, f2, … , fx, …, fn],它保存的对象是第二个箭头函数返回的匿名函数。因为是闭包,所以每个匿名函数都可以访问相同的store。

组合串联middleware

dispatch = compose(...chain)(store.dispatch);

compose是函数式编程中的组合,它将chain中的所有匿名函数组合成一个新的函数,也就是新的dispatch。当新的dispatch执行的时候,chain中的函数从fn到f1依次执行。

在middleware中调用dispatch会发生什么

在middleware中使用dispatch的场景一般是接收到一个定向action,这个action并不希望到达原生的分发action,往往用在异步请求的需求里。

Redux异步流

使用middleware简化一步请求

常用的3个middleware:

redux-thunk

redux-promise

异步请求其实都是利用promise完成的,那么为什么不通过抽象promise来解决异步流的问题呢?

这里引入redux-promise middleware,源码如下:

这里写图片描述

redux-promise将返回的结果保存在payload中。

实现过程:判断action或者action.payload是否为promise,如果是,就执行then,返回的结果再发送一次dispatch。

redux-composable-fetch

结合上述讨论的两个开源middleware,我们完全可以自己实现一个更贴合工程需要的middleware,这里我们将其命名为fetch。

在理想情况下,我们不希望通过复杂的方式去请求数据,而是希望通过如下形式一并完成在异步请求过程中的不同状态。

{    url: '/api/weather.json',     params: {        city: encodeURI(city),    },    types: ['GET_WEATHER', 'GET_WEATHER_SUCESS', 'GET_WEATHER_ERROR'], }

在请求middleware中,会对action进行格式检查,如果存在url和type属性,则说明这个action是一个用于发送异步请求的action。此外,并不是所有的请求都能携带参数,所以params是可选的。

当请求middleware识别到这是一个用于发送请求的action后,首先会分发一个新的action,这个action的type就是原action里types数组的第一个元素,也就是请求中。分发这个新的action的目的在于让store能够同步到当前请求的状态。

然后,请求middleware会根据action中的url, params, method等参数发送一个异步请求,并在相应后根据结果的成功和失败分发新的action。