思想

应用中所有的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. 【每天一题】LeetCode 0028. 字符串匹配

    开源地址:https://github.com/jiauzhang/algorithms 题目描述 * https://leetcode-cn.com/problems/implement-strst ...

  2. 流式计算(一)-Java8Stream

    大约各位看官君多少也听说了Storm/Spark/Flink,这些都是大数据流式处理框架.如果一条手机组装流水线上不同的人做不同的事,有的装电池,有的装屏幕,直到最后完成,这就是典型的流式处理.如果手 ...

  3. Shell命令的执行优先级

    Shell内置命令.外部命令.别名.函数.保留关键字的优先级 在Shell中,有5种可调用的东西:别名(alias).函数(function).shell保留关键字.shell内置命令.外部命令. 如 ...

  4. Additional information: The maximum message size quota for incoming messages (65536) has been exceeded. To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding elemen

    wcf service: <system.serviceModel> <bindings> <basicHttpBinding> <binding name= ...

  5. How to: Handle Renamings and Deletions of Business Classes and their Properties 如何:处理业务类及其属性的重命名和删除

    When developing an XAF application, you may be required to rename a persistent class or property due ...

  6. OpenTSDB 简单使用 .NET

    OpenTSDB是基于Hbase的时序数据库[时间序列数据库].不具备通用性,主要针对具有时间特性和需求的数据,如监控数据.温度变化数据等. 1.安装OpenTSDB 安装前一定要安装HBase,相关 ...

  7. XTTS Creates Alias on Destination when Source and Destination use ASM (Doc ID 2351123.1)

    XTTS Creates Alias on Destination when Source and Destination use ASM (Doc ID 2351123.1) APPLIES TO: ...

  8. liunxCPU和内存,磁盘等资源

    1.Screen是一款由GNU计划开发的用于命令行终端切换的自由软件.用户可以通过该软件同时连接多个本地或远程的命令行会话,并在其间自由切换.GNU Screen可以看作是窗口管理器的命令行界面版本. ...

  9. Linux系统学习 十七、VSFTP服务—本地用户访问—用户访问控制

    FTP相关文件中用户控制列表文件 /etc/vsftpd/ftpusers        #该文件永远都是黑名单(针对访问ftp服务,一般不做修改) /etc/vsftpd/user_list     ...

  10. 基于django的个人博客网站建立(六)

    基于django的个人博客网站建立(六) 前言 今天主要完成的是项目在腾讯云服务器上ubuntu16.04+django+mysql+uwsig+nginx的部署过程网站效果可点击这里访问 主要内容 ...