Redux 是一种前端“架构模式”,是 Flux 架构的一种变种,用来提供可预测的状态管理。虽然经常和 React 一起被提及,但是 Redux 却不仅仅只能用于 React,还可以将其运用到其他前端库中,Vue Angular甚至是 jQuery。Redux 只是一种架构模式而已,并没有和其他库绑定在一起。而 React-redux 就是把 Redux 和 React.js 结合起来的一个库。就像 Vuex 一样,是一个与 Vue.js 结合的 Flux变种。

为什么要用 Redux

也许有人会问:为什么我们会需要 redux 呢?  嗯... 确实,我们必须要先了解我们为什么需要 redux? redux 的出现是为了解决什么问题?

那么,我们来考虑这么一种场景,在你构建的一棵组件树中,有A、B那么两个组件,它们需要共享同一个状态,你会怎么办呢?

我们可以通过状态提升的思路,将该状态提升到附近的公共父组件上面,然后通过 props 把状态传递给子组件,这样就可以在A、B组件之间共享数据了。确实可以,但是如果A、B的父组件在组件树向上好几个组件的位置呢?就需要将状态通过 props 一级一级往下传递,那么状态的传递路径就会非常长,而且中间组件根本就不需要访问这个状态。而且,如果后续有一个 C 组件也要访问该状态并且A、B、C的公共父组件还要往上呢?你就不得不修改之前代码了。很显然,这不是一种很好的解决方案,它会让我们的代码维护起来非常痛苦。

难道就没有其他方法可以解决这个问题吗?其实也有的,那就是 react 的 context,一个组件只要往自己的 context 里面放了某些状态,那么这个组件的所有子组件都可以直接访问这个状态而不需要通过中间组件的传递,看起来问题解决了嘛。

我们虽然解决了状态传递的问题却引入了新的问题,我们引入的 context 打破了组件和组件之间通过 props 传递数据的规范,极大地增强了组件之间的耦合性。而且 context 就像全局变量一样,里面的数据可以被子组件随意更改,可能会导致程序不可预测的运行。

这时候我们就该考虑使用 Redux 了,Redux 可以帮你创建应用的共享状态,并且不能随意的更改这些状态

Redux 的基本概念

我们已经了解了为什么要使用 Redux,那么我们先了解下 Redux 的三个基本概念。

Store

我们可以通过 createStore 来创建 store

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

在 Redux 中,应用程序只能拥有一个 store,用来保存整个应用程序的 state,相当于一个应用程序的共享状态。

我们可以通过 store.getState() 来获取应用程序的当前状态。但是我们却不能随意的修改状态,我们只能通过 store.dispatch(action) 来修改状态。

修改完状态之后,我们希望可以做些 view 层的改变,这时可以通过 store.subscribe(() => {}) 来注册视图变化的回调函数。

Actions

Actions 是一个 JavaScript 普通对象,用来描述应用程序中发生的一些事情,也是把数据从应用传递给 store 的唯一途径。

我们约定,action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作,type 一般会被定义成字符串常量。

const ADD_TODO = 'ADD_TODO'

{
type: ADD_TODO,
data: 'some data'
}

我们除了直接以 JavaScript 普通对象的形式来定义 action 之外,也可以通过函数形式来定义 action,这个函数被称作 Action 创建函数( actionCreator )。

const ADD_TODO = 'ADD_TODO';

function addTodo(data) {
return {
type: ADD_TODO,
data
}
}

这里 action 创建函数 addTodo 很简单,只是返回一个 action。 我们可以通过 store.dispatch 来通知需要修改状态

store.dispatch(addTodo('some data'));

Reducers

我们已经知道可以通过 action 来修改状态,但是 action 传递过来的只是简单的对象,并没有具体处理状态的逻辑,这就是 reducers 要做的事情了。

Reducer 必须是一个纯函数(一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用,这个函数就叫做纯函数)。因为纯函数非常“靠谱”,执行一个纯函数不会产生不可预料的行为,也不会对外部产生影响。

function todoApp(state = { title: 'todoApp', todos: [] }, action) {
switch (action.type) {
case ADD_TODO:
return Object.assign({}, state, {
todos: [
...state.todos,
{
data: action.data,
completed: false
}
]
})
default:
return state
}
}

todoApp 接收旧的 state 和 action,并返回新的state。注意这里我们是将 state 拷贝一份,再添加我们改动的值去覆盖原来的数据,重新组合成新的 state 返回,而不是直接修改 state。

这是因为如果你直接去改变 state 里对象的属性,那么就需要去比较新旧两个 state 的区别,而比较两个 Javascript 对象所有的属性是否相同就需要对它们进行深比较。但是在真实的应用中 js 的对象都很大,进行深比较的代价十分昂贵。而如果你返回的是一个全新的对象,就只需要比较新旧两个对象的存储地址是否相同就可以了。Redux 就是这么做的,如果你在 reducer 内部直接修改旧的 state 对象的属性值,那么新的 state 和旧的 state 将都指向同一个存储地址,Redux 会认为没有任何改变。

我们可以有多个 reducer,每个 reducer 只负责管理全局 state 中它负责的那部分,每个 reducer 的 state 参数可以都不同,分别对应它管理的那部分 state 数据。然后通过 combineReducers 组成根 reducer 用来创建一个store。

import { combineReducers } from 'redux';

const todosReducer = (state = [], action) => {
// do something
} const titleReducer = (state = '', action) => {
// do something
} const reducer = combineReducers({
todos: todosReducer,
title: titleReducer
}); // 等价于
function reducer(state = {}, action) {
return {
todos: todosReducer(state.todos, action),
title: titleReducer(state.title, action)
}
}

combineReducers 这个函数会调用你的定义的 reducer,每个 reducer 根据它们的 key(todos, title) 来筛选出 state 中的一部分数据处理并返回一份副本,根 reducer 会把这些副本组合起来形成一个新的大对象。最后根 reducer 将这个大对象传回给 store,store 再将它设为最终的状态。

Redux 工作流程

redux 一些基本概念我们都清楚了,我们来总结一下,Redux 为我们所做的事情:

1.  一个存放应用程序共享 state 的地方
2. 一个去分发 actions 通过纯函数修改应用程序共享 state 的机制
3. 一个可以订阅 state 更新的机制

严格的单向数据流是 Redux 架构的设计核心

我们只要清楚了 redux 中的数据流动的过程就明白 redux 整个工作流程了,我们从产生一个 action 的切入点来分析数据是怎样流动的。

1. 通过用户在视图层的交互产生了一个 action,这个 action 可能是通过 actionCreator 返回的。

2. store 接受这这个 action 之后,将当前的 state 和 action 一起传递给根 reducer。

3. 根 reducer 将 state 分配给子 reducer 进行处理,子 reducer 返回修改后的副本给根 reducer,根 reducer 整合子 reducer 返回的副本生成一个新的 state 副本返回给 store。

4. store 根据新的 state 触发视图层的渲染。

5. 用户看到交互后视图的变化,又高兴地发起了一个 action ...

更多精彩内容,欢迎关注微信公众号~

 

Redux 架构理解的更多相关文章

  1. React-redux: React.js 和 Redux 架构的结合

    通过Redux 架构理解我们了解到 Redux 架构的 store.action.reducers 这些基本概念和工作流程.我们也知道了 Redux 这种架构模式可以和其他的前端库组合使用,而 Rea ...

  2. 用原生JS从零到一实现Redux架构

    前言 最近利用业余时间阅读了胡子大哈写的<React小书>,从基本的原理讲解了React,Redux等等受益颇丰.眼过千遍不如手写一遍,跟着作者的思路以及参考代码可以实现基本的Demo,下 ...

  3. Redux架构

    深入Redux架构   阅读目录 关于redux API 中间件与异步操作 异步操作的基本思路 React-Redux的用法 回到顶部 关于redux 之前写了一篇通过一个demo了解Redux,但对 ...

  4. 在 React Native 中使用 Redux 架构

    前言 Redux 架构是 Flux 架构的一个变形,相对于 Flux,Redux 的复杂性相对较低,而且最为巧妙的是 React 应用可以看成由一个根组件连接着许多大大小小的组件的应用,Redux 也 ...

  5. TAF /tars必修课(一):整体架构理解

    来自零点智能社区 一.前言 TAF,一个后台逻辑层的高性能RPC框架,目前支持C++,Java, node 三种语言, 往后可能会考虑提供更多主流语言的支持如 go等,自定义协议JCE,同时也支持HT ...

  6. 沉淀再出发:Spring的架构理解

    沉淀再出发:Spring的架构理解 一.前言 在Spring之前使用的EJB框架太庞大和重量级了,开发成本很高,由此spring应运而生.关于Spring,学过java的人基本上都会慢慢接触到,并且在 ...

  7. redux的理解

    Redux 这里介绍下我对Redux的理解,不涉及如何使用Redux. Redux 官网介绍: A predictable state container for JavaScript apps.(一 ...

  8. ARM CORTEX-M3 内核架构理解归纳

    ARM CORTEX-M3 内核架构理解归纳 来源:网络 个人觉得对CM3架构归纳的非常不错,因此转载 基于<ARM-CORTEX M3 权威指南>做学习总结: 在我看来,Cotex-M3 ...

  9. RESTful 架构理解

    REST中的关键词: 1.资源 2.资源的表述 3.状态转移 资源: "资源",可以是一段文本.一张图片.一首歌曲.一种操作.你可以用一个URI(统一资源定位符)指向它,每种资源对 ...

随机推荐

  1. 信贷建模little tricks

    一.逻辑回归 概率分类模型 选取样本:对逻辑回归这种概率分类模型来说维持原来样本真实的分布还是有必要的,但是对一些树模型来说可以通过采样来平衡样本. 原来评分卡建模还有个拒绝推断,就是为了还原人群真实 ...

  2. 【一定要记得填坑】LG_3822_[NOI2017]整数

    挺好的一道题,由于快noip了,所以打算noip之后再添题解的坑.

  3. jquery mobile AJAX特性的陷阱

    简单情况是 MVC 重定向,URL不变 试了N种方式,跳来跳去,无解,服务端跳,写JS跳,生成跳转中间页跳.失败 后来一看,明明已经跳到新页了,样式什么还是原页的,有点火大了. 出去溜一圈,喝杯水,和 ...

  4. 常胜将军的深思变局:OPPO的渐变释放了怎样的行业信号?

    在经过了前几年的狂飙突进后,当下手机行业已经步入了自身的"十年之痒"阶段.利润贴地飞行.T型格局已定且竞争者实力愈强.创新不明显导致消费者换新驱动力降低.全球化竞争趋势凸显-- 也 ...

  5. dubbo分布式框架下web层调用业务层一直报空指针异常的解决办法

    java.lang.NullPointerException............... 环境:SSM(通用mapper)+Dubbo 1.检查导包 提示注解@Reference  应该导入  im ...

  6. Android ListView 常用技巧总结

    本文对 ListView 中的一些常用技巧做一个总结.附:虽然现在 RecyclerView 已逐渐取代 ListView,但实际情况是大部分项目中还在使用 ListView.当然,后续我会在我的博客 ...

  7. 吴裕雄--天生自然 R语言开发学习:方差分析

    #-------------------------------------------------------------------# # R in Action (2nd ed): Chapte ...

  8. webgrind安装使用详细说明

    webgrind是一个网页版的性能分析工具,它的主要作用就是分析xdebug生成的cachegrind文件,以一种界面友好详尽的方式来展示性能数据.试用了一下感觉还是很不错的,鉴于网上并没有一个系统介 ...

  9. SpringBoot + JPA + mariadb

    SpringBoot + JPA + MariaDB 源码:https://github.com/ldl326308/LiveGreen-SpringBoot.git JPA持久层方法名命名规则:

  10. Spring MVC 增加静态资源配置mvc:resources跳转不了链接

    在使用mvc:resources 要配合 <mvc:annotation-driven/> 一起