思想

应用中所有的state都以一个对象树的形式储存在一个单一的store中。唯一能改变state的办法是触发action,一个描述发生什么的对象。为了描述action如何改变state树,需要编写reducers。

Redux只有一个单一的store和一个根级的reduce函数(reducers)。随着应用的不断增大,应该把根级的reducer拆分成多个小的reducers,分别独立的操作state树的不同部分,而不是添加新的stores。

三大原则

单一数据源

整个应用的state被储存在一棵object tree中,并且这个object tree只存在于唯一一个store中。来自服务端的state可以在无需编写更多代码的情况下被序列化并注入到客户端中。

State是只读的

唯一改变state的方法就是出发action,action是一个用于描述已发生事件的普通对象。这样确保了视图和网络请求都不能直接修改state,相反它们只能表达想要修改的意图。

使用纯函数来执行修改

为了描述action如何改变state tree,需要编写reducers。Reducer只是一些纯函数,它接受先前的state和action,并返回新的state。

基础

Action

Action是把数据从应用传到store的有效载荷。它是state数据的唯一来源。一般通过store.dispatch()将action传到store。Action本质上是JavaScript普通对象。action内必须有一个字符串类型的type字段来表示将要执行的动作。多数情况下type会被定义成字符串常量。当应用规模变大时,可以使用单独的模块或文件存放action。

我们还需要添加一个action index字段来表示用户完成任务的动作序列号。因为数据是存放在数组中的,所以我们通过下标index哎引用特定的任务。而实际项目中一般会在新建数据的时候生成唯一的ID作为数据的引用标识。

{
   type: TOGGLE_TODO,
   index:5
}

我们应该尽量减少在action中传递的数据。传递index比传递整个任务对象要好。

Action创建函数

Action创建函数就是生成action的方法。在Redux中的action创建函数只是简单的返回一个action:

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

这样做是action创建函数更容易被移植和测试。在传统的Flux中,当调用action创建函数时,一般会触发一个dispatch:

function addTodoWithDispatch(text) {
   const action = {
       type: ADD_TODO,
       text
  }
   dispatch(action)
}

Redux中只需要把action创建函数的结果传递给dispatch()方法即可触发一次dispatch过程:

dispatch(addTodo(text))
dispatch(completeTodo(index))

或是创建一个被绑定的action来自动dispatch:

const boundAddTodo = text => dispatch(addTodo(text))
const boundCompleteTodo = index => dispatch(completeTodo(index))

store里能直接通过store.dispatch()调用dispatch()方法,但是多数情况下会使用react-redux提供的connect()帮助器来调用。BindActionCreators()可以自动把多个action创建函数绑定到dispatch()方法上。

Reducer

Reducers指定了应用状态的变化如何响应actions并发送到store,actions只是描述了有事情发生了这一事实,并没有描述应用如何更新state。

在Redux应用中,所有的state都被保存在一个单一对象中,在写代码前应该先想一下这个对象的结构。如何才能以最简的形式把应用的state用对象描述出来。

以todo应用为例,需要保存两种不同的数据:

  • 当前选中的任务过滤条件;

  • 完整的任务列表。

通常这个state树还需要存放其它的一些数据,以及一些UI相关的state。尽量把这些数据与UI相关的state分开。

{
 visibilityFilter: 'SHOW_ALL',
 todos: [
  {
     text: 'Consider using Redux',
     completed: true,
  },
  {
     text: 'keep all state in a single tree',
     completed: false
  }
]
}

Action处理

确定了state对象的结构,就可以开始开发reducer。reducer就是一个纯函数,接受旧的state和action,返回新的state。

(previousState, action) => newState

保持reducer纯净非常重要,所以永远不要在reducer中做这些事:

  • 修改传入参数;

  • 执行有副作用的操作;

  • 调用非纯函数。

只要传入参数相同,返回计算得到的下一个state就一定相同。没有特殊情况,没有副作用,没有API请求,没有变量修改,单纯执行计算。

Store

使用action来描述“发生了什么”,使用reducer来根据action更新state的用法。Store就是把它们联系在一起的对象。Store有以下职责:

  • 维持应用的state;

  • 提供getState()方法获取state;

  • 提供dispatch()方法更新state;

  • 通过subscribe(listener)注册监听器;

  • 通过subscribe(listener)返回的函数注销监听器。

Redux应用只有一个单一的store。当需要拆分数据逻辑时,应该使用reducer组合而不是创建多个store。

数据流

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

这意味着应用中所有的数据都遵循相同的声明周期,这样可以让应用变得更加可预测且同意理解。同时也鼓励做数据规范化,这样可以避免使用多个独立且无法相互引用的重复数据。

Redux应用中数据的声明周期遵循4个步骤:

1、调用store.dispatch(action)

2、Redux store调用传入的reducer函数。

3、根reducer应该把多个子reducer输出合并成一个单一的state树。

4、Redux store保存了根reducer返回的完整state树。

搭配React

Redux支持React、Angular、Ember、JQuery甚至是纯JavaScript。但是React允许以state函数的形式来描述界面,Redux通过action的形式来发起state变化。

安装React-Redux:

npm install --save react-redux

Redux的React绑定库是基于容器组件和展示组件相分离的开发思想,这个思想非常重要。

  展示组件 容器组件
作用 描述如何展现(骨架、样式) 描述如何运行(数据获取、状态更新)
直接使用Redux
数据来源 props 监听Redux state
数据修改 从props调用回调函数 向Redux派发actions
调用方式 手动 通常由React Redux生成

大部分的组件都应该是展示型的,但一般需要少数的几个容器组件把它们和Redux store连接起来。

例如,我们想要显示一个todo项的列表。一个todo项被点击后,会增加一条删除线并标记为completed。我们会显示用户增加一个todo字段。在footer里显示一个可切换的显示全部/只显示completed的/只显示incompleted的todos。

展示组件和他们的props:

  • TodoList用于显示todos列表。

    • todos: Array{ text, completed }形式显示的todo项数组。

    • onTodoClick(index: number)当todo项被点击时调用的回调函数。

  • Todo一个todo项。

    • text: string显示的文本内容。

    • completed: booleantodo项是否显示删除线。

    • onClick()当todo项被点击时调用的回调函数。

  • Link带有callback回调功能的链接。

    • onClick()当点击链接时会触发。

  • Footer一个允许用户改变可见todo过滤器的组件。

  • App根组件,渲染余下的所有内容。

这些组件只定义外观不关心数据来源和如何改变。传入什么就渲染什么。如果把代码从Redux迁移到别的结构。这些组件可以不做任何改动的直接使用。

容器组件:

还需要一些容器组件来把展示组件连接到Redux。例如,展示型的TodoList组件需要一个类似VisibleTodoList的容器来监听Redux store变化并处理如何过滤出要显示的数据。为了实现状态过滤,需要实现FilterLink的容器组件来渲染Link并在点击时触发对应的action:

  • VisibleTodoList根据当前显示的状态来对todo列表进行过滤,并渲染TodoList

  • FilterLink得到当前过滤器并渲染Link

    • filter: string就是当前过滤的状态。

其它组件:

有时候表单和函数严重耦合在一起,很难分清该使用容器组件还是展示组件:

  • AddTodo含有“Add”按钮的输入框。

Redux使用的更多相关文章

  1. RxJS + Redux + React = Amazing!(译一)

    今天,我将Youtube上的<RxJS + Redux + React = Amazing!>翻译(+机译)了下来,以供国内的同学学习,英文听力好的同学可以直接看原版视频: https:/ ...

  2. 通过一个demo了解Redux

    TodoList小demo 效果展示 项目地址 (单向)数据流 数据流是我们的行为与响应的抽象:使用数据流能帮我们明确了行为对应的响应,这和react的状态可预测的思想是不谋而合的. 常见的数据流框架 ...

  3. RxJS + Redux + React = Amazing!(译二)

    今天,我将Youtube上的<RxJS + Redux + React = Amazing!>的后半部分翻译(+机译)了下来,以供国内的同学学习,英文听力好的同学可以直接看原版视频: ht ...

  4. redux学习

    redux学习: 1.应用只有一个store,用于保存整个应用的所有的状态数据信息,即state,一个state对应一个页面的所需信息 注意:他只负责保存state,接收action, 从store. ...

  5. webpack+react+redux+es6开发模式

    一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...

  6. Redux初见

    说到redux可能我们都先知道了react,但我发现,关于react相关的学习资料很多,也有各种各样的种类,但是关于redux简单易懂的资料却比较少. 这里记录一下自己的学习理解,希望可以简洁易懂,入 ...

  7. react+redux教程(八)连接数据库的redux程序

    前面所有的教程都是解读官方的示例代码,是时候我们自己写个连接数据库的redux程序了! 例子 这个例子代码,是我自己写的程序,一个非常简单的todo,但是包含了redux插件的用法,中间件的用法,连接 ...

  8. react+redux教程(七)自定义redux中间件

    今天,我们要讲解的是自定义redux中间件这个知识点.本节内容非常抽象,特别是中间件的定义原理,那多层的函数嵌套和串联,需要极强逻辑思维能力才能完全消化吸收.不过我会多罗嗦几句,所以不用担心. 例子 ...

  9. react+redux教程(六)redux服务端渲染流程

    今天,我们要讲解的是react+redux服务端渲染.个人认为,react击败angular的真正“杀手锏”就是服务端渲染.我们为什么要实现服务端渲染,主要是为了SEO. 例子 例子仍然是官方的计数器 ...

  10. react+redux教程(五)异步、单一state树结构、componentWillReceiveProps

    今天,我们要讲解的是异步.单一state树结构.componentWillReceiveProps这三个知识点. 例子 这个例子是官方的例子,主要是从Reddit中请求新闻列表来显示,可以切换reac ...

随机推荐

  1. RocketMq在SparkStreaming中的应用总结

    其实Rocketmq的给第三方的插件已经全了,如果大家有兴趣的话请移步https://github.com/apache/rocketmq-externals.本文主要是结合笔者已有的rmq在spar ...

  2. asp.net core使用serilog将日志推送到腾讯云日志服务

    为什么是serilog? Serilog是 .NET 中最著名的结构化日志类库. 基于日志事件log events,而不是日志消息log message. 你可以将日志事件格式化为控制台的可读文本或者 ...

  3. 如何判断IE OCX插件正常安装?

    项目中用到了一个第三方的ie ocx控件,而经常遇到客户和测试小伙伴反馈相关功能无法正常使用,也没有友好提示.考虑到这个问题,必须要有一个ie ocx控件的检查机制. 检查原理 创建ActiveXOb ...

  4. 死磕 java线程系列之线程池深入解析——构造方法

    (手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 简介 ThreadPoolExecutor的构造方法是创建线程池的入口,虽然比较简单,但是信息量很大,由此也能 ...

  5. springboot~mybatis枚举映射

    在mybatis和mybatis plus里,如果你的实体字段是一个枚举类型,而在数据表里是整型,这时在存储时需要进行处理,默认情况下,会把枚举的元素名称拼接到SQL语句里,而由于数据表是int类型, ...

  6. English: Class words

    filing cabinet pan drive penalty charge per annum light setting remote control

  7. 内存取证工具-volatility、foremost

    内存取证 1. 内存取证工具volatility 猜测dump文件的profile值 root@kali:~/CTF# volatility -f mem.vmem imageinfo Volatil ...

  8. 小程序模板template使用介绍

    template(模板):是可以在wxml中引用的代码,就是在wxml中引用公用的wxml类型的代码,它的作用类似于组件,因此这里简单的说明下template与Component (组件)的区别. t ...

  9. 2019/12/13学习内容摘要(Linux磁盘管理①)

    一,查看磁盘或目录容量 1.命令df  查看已挂载磁盘的总容量,使用容量,剩余容量等,可以不加任何参数,默认以KB为单位 选项[-i] 表示查看inodes的使用情况 [-h] 表示用合适的单位显示 ...

  10. 【问题解决】vim 打开文档后提醒 E325: ATTENTION 怎么办?

    这是经典的 vi/vim 的报错情形. 在 Linux 下,使用 vim 或是 vi 查看文件时,可能每次都会出现下面贴出的 E325 错误提醒,然后按 E 进行 Edit anyway 才能继续读写 ...