【天赢金创】React flux九浅一深

这个是 Facebook 官方学习 Flux 的 todo 例子

想用这个例子来总结一下怎么从零开始用 React 和 Flux 构建一个 App

Structure

App
├─ javascripts
│  ├─ actions
│  │  ├─ TodoActions.js
│  ├─ components
│  │  ├─ TodoComponents
│  │  │  ├─ TodoApp.js
│  │  │  ├─ Header.js
│  │  │  ├─ MainSection.js
│  │  │  ├─ Footer.js
│  │  │  ├─ TodoItem.js
│  │  │  ├─ TodoTextInput.js
│  ├─ constants
│  │  ├─ TodoConstants.js
│  ├─ dispatcher
│  │  ├─ AppDispatcher.js
│  ├─ stores
│  │  ├─ TodoStore.js
├─ stylesheets
│  ├─ TodoStyle.css
├─ index.html
├─ README.md
├─ package.json
├─ webpack.config.js

可能你看到的这个结构和官方 demo 的结构会有点不同,那是因为官方的 demo 整个的本身只有 todo 这个功能,但实际上远远不至。所以在 components 下会细分是什么部分的组件,像 TodoComponents

关于 Flux 里的 Action, Dispatcher, Store and Controller View 这些概念如果还不了解的话可以去看看这两篇文章

Components

首先你通过你 app 的界面来确定你的组件,如下图

从这个图我们可以看到,我们的组件有

  • Header
  • MainSection
  • Footer
  • TodoItem
  • TodoTextInput

在 MainSection 里有 TodoTextInput 是当我们双击我们已经存在的 todo,可以对其进行更新

Actions

确定了组件之后,我们就可以确定我们的 TodoActions 文件了。

对于这个 Todo app,有多少 actions 呢?

  • create - 我们可以创建一条新的 todo
  • updateText - 双击已经存在的 todo,可以对其进行更新
  • toggleComplete - 看到每一条前面的勾勾了吗?就是可以给你决定是否完成了
  • toggleCompleteAll - 看到输入框前面那个 ? 了吗?就是让你全部完成,或者全部不完成的
  • destroy - 看到每一条后面那个叉叉了吗?要 hover 在上面才看到的,就是给你删除这一条的
  • destroyCompleted - 看到 Footer 下面那个 Clear completed 了吗?就是给我们删除已经完成的 todo 的

就是这样,我们根据我们的需求在这个文件里定义不同的 action 函数,但这里的函数并不涉及逻辑的处理,这里函数只是告诉我们的 Dispatcher,用户进行了什么操作。所以我们只需要给 Dispatcher 传的一个对象,对象里一个必要的属性就是 actionType。如果用户进行这个操作有给我们传的参数的话。那参数也会放在这个对象里。

例如用户想创建一条新的 todo ,就是我们的 create action 了

import AppDispatcher from ‘../dispatcher/AppDispatcher‘; import TodoConstants from ‘../constants/TodoConstants‘; var TodoActions = {
  create (text) {
    AppDispatcher.dispatch({
      actionType: TodoConstants.TODO_CREATE,
      text: text
    });
  }, // other actions } export default TodoActions;

当我们执行 AppDispatcher.dispatch 这个方法,并传给他一个有 actionType 属性的对象时,他就会在大喊,“有人做了一个操作呀,这个操作就是 xxx (actionType 的值),还带了个参数,你们哪个来处理一下呀”

嗯嗯,就是这样,数据就从 Action 传到了 Dispatcher

Dispatcher

Dispatcher 的具体实现可以看 github.com/facebook/flux/blob/master/src/Dispatcher.js

游客只可以贴两个链接,我也是醉

当我们用 Facebook 给我们提供的 Dispatcher,那么一切都会变得简单了许多

npm install --save flux
import Flux from ‘flux‘; var Dispatcher = Flux.Dispatcher; export default new Dispatcher();

Dispatcher 在整个应用

只有一个,只有一个,只有一个

有人就说了,你 Dispatcher 只负责喊的,我不要你也好像可以呀。嗯嗯,那就不叫 Fulx 了,叫 Reflux github.com/spoike/refluxjs

Constants

刚刚我们看到在我们的 Actions 里,actionType: TodoConstants.TODO_CREATE,这个 TodoConstants 其实就是我们操作的名字,相当于一个常量,定义在 Constants 里方便管理和调用而已。

一般你有多少个 action,就有多少个常量在这个 Constants 里

KeyMirror 就是创建一个对象,里面键的值等于键的名字 - -

Stores

主角登场! 但, Store 是什么?

Store 是一个保存数据的地方

var _todo = {};

Store 是一个充满逻辑的地方

所有 actions 的逻辑处理,都会在这里发生。像我们的 create action

function create (text) { var id = (new Date() + Math.floor(Math.random() * 999999)).toString(36);
  _todos[id] = {
    id: id,
    complete: false,
    text: text
  };
}

Store 是一个响应 Dispatcher 呼喊的地方

“有人做了一个操作呀,这个操作就是 xxx (actionType 的值),还带了个参数,你们哪个来处理一下呀”

在 Store 里,我们通过 Dispatcher “注册”了一个回调函数,每当我们调用 dispatch 函数的时候,就是 Dispatcher 大喊的时候,我们根据不同的 actionType,来调用我们不同的逻辑处理函数,像这样

import AppDispatcher from ‘../dispatcher/AppDispatcher‘; import TodoConstants from ‘../constants/TodoConstants‘;

AppDispatcher.register((action) => { var text; switch(action.actionType) { case TodoConstants.TODO_CREATE:
      text = action.text.trim(); if (text !== ‘‘) {
        create(text);
        TodoStore.emitChange();
      } break; // other case }
});

Store 是一个鞭策 Controller View 改变的地方

每当 Store 改变了数据之后,他都要 Controller View 跟着他改变。他们还约定了暗号

var CHANGE_EVENT = ‘change‘;

Store 跟 Controller View 说,我一喊 “变”,你听到之后,你就叫你的手下一起变。

Controller View 说好。

但是 Store 不会喊,Controller View 也听不到。

所以 Store 从 EventEmitter中学会了喊,也给 Controller View 买来了助听器

import assign from ‘object-assign‘; var EventEmitter = require(‘events‘).EventEmitter; var TodoStore = assign({}, EventEmitter.prototype, {
  areAllComplete () { for (var id in _todos) { if (!_todos[id].complete) { return false;
      }
    } return true;
  },
  getAll () { return _todos;
  },
  emitChange () { this.emit(CHANGE_EVENT);
  },
  addChangeListener (callback) { this.on(CHANGE_EVENT, callback);
  },
  removeChangeListener (callback) { this.removeListener(CHANGE_EVENT, callback);
  }
}); export default TodoStore;

所以每当执行完逻辑处理函数之后,Store 都会喊一句 TodoStore.emitChange();

助听器 addChangeListener (callback) { this.on(CHANGE_EVENT, callback) } 也买好了,成不成功,就看 Controller View 了

Controller View

在 Components 里,你看不到 TodoApp 这个组件,因为对于 Todo 这个 App,TodoApp 这个组件,就是 Contriller View,他掌管全部的 Components。

但是重要的是,他怎么带 Store 给他买的助听器

componentDidMount () {
  TodoStore.addChangeListener(this._onChange.bind(this));
}

当组件渲染完成后,就绑定了 Store 的 addChangeListener,并回调了自己的 onChange 方法。

_onChange () { this.setState(this.getTodoState.bind(this)());
}

Store 一喊,Controller View 听到之后,更新所有数据,以 props 的方式传给他的手下 - 即他掌管的 Components

Summary

现在我们来疏理一下整个流程(就 create 而言)

  1. 用户输入要新增的 todo,一敲回车,触发 onKeydown 方法。
  2. onKeydown 调用了 onSave 方法,onSave 调用了 TodoActions.create 方法。
  3. TodoActions.create 触发了 AppDispatcher.dispatch 方法,AppDispatcher 大喊了一声。
  4. TodoStore 响应,根据 actionType 调用了 create 逻辑处理函数,执行完,喊了一句 “变”。
  5. Controller View 带着助听器听到了接着更新数据,把数据传给了各个 Components。
  6. 重新渲染,新增完毕。

以上是本人浅显的理解,如有错误,欢迎指正 : )

时间: 2024-09-28 07:11:53

【天赢金创】React flux九浅一深的相关文章

【天赢金创】10 条真心有趣的 Linux 命令

在终端工作是一件很有趣的事情.今天,我们将会列举一些有趣得为你带来欢笑的Linux命令. 1. rev 创建一个文件,在文件里面输入几个单词,rev命令会将你写的东西反转输出到控制台. # rev <file name> Selection_002 Selection_001 2. fortune 这个命令没有被默认安装,用apt-get命令安装它,fortune命令会随机显示一些句子 [email protected]:~$ sudo apt-get install fortune Sele

【天赢金创】面向对象的程序设计之创建对象

对象的定义:无序属性的集合,属性的值可以是基本值.对象或者函数. 每个对象都是基于一个应用类型创建的,这个引用类型可以是内置的(例如Object Array Math),也可以是用户自定义的. 基于Object创建对象 所有的对象都是继承自Object的,因此我们可以从Object着手创建对象. //通过new 关键字创建对象 var person = new Ojbect(); person.name = 'yuhualinfeng'; person.age = 30; person.job

Dagger 2从浅到深(七)

在使用Dagger 2开发时,一般都是在Application中生成一个AppComponent,然后其他的功能模块的Component依赖于AppComponent,作为AppComponent的子组件.可是,对于将自组建添加到父组件有两种方式: 通过@Component的dependencies属性依赖父组件 @Component(modules = OrangeModule.class, dependencies = FruitComponent.class) public interfa

浅入深出ElasticSearch构建高性能搜索架构

浅入深出ElasticSearch构建高性能搜索架构  课程学习地址:http://www.xuetuwuyou.com/course/161 课程出自学途无忧网:http://www.xuetuwuyou.com 一.课程用到的软件 ElasticSearch5.0.0 Spring Tool Suite 3.8.2.RELEASE Maven3.0.5 Spring4 Netty4 Hadoop2.7.1 Kibana5.0 JDK1.8.0_111 二.课程目标 1.快速学习Elastic

由浅到深学习JDBC二

封装数据访问对象 1:通过分析总结,所有对数据库表的操作都可以总结为通过JDBC对表的增删改查,为了减少冗余代码, 使得每次操作表时,不必都写JDBC程序,所以将对一张表的所有数据访功能,封装在数据访问对象 (Data Access Object)中,方便调用. 2:为了方便数据传输,往往会将java程序中所有相关操作的零散字段值,封装成一个实体对象--entity. 实体封装原则: 表----实体类 字段---属性 实现序列化 提供set,get方法. 以下代码就是利用Dao数据访问对象写出的

由浅到深学习JDBC一

JDBC: 虽然由于快节奏的开发,编程速度的追求,越爱越多的MVC框架出现,比如持久层的hibernate, mybatis等等,他们对Dao层的支持都很强大,既快速,又简便.但是他们的底层同样是使用了JDBC, 为了追求高速简便,我们可以不使用JDBC,但一定要了解JDBC.了解JDBC也有助于学习其他持久层框架. java和数据库交互需要中间程序作为中转.在很早以前,数据库厂商还没有一套统一的API作为 java语言和数据库的接口,开发程序是一件很头疼的事.对不同的数据库需要写不同的程序来作

SE壳C#程序-CrackMe-爆破 By:凉游浅笔深画眉 / Net7Cracker

[文章标题]: [SE壳C#程序-CrackMe-爆破]文字视频记录![文章作者]:  凉游浅笔深画眉[软件名称]: CM区好冷清,我来发一个吧!小小草莓[下载地址]: http://www.52pojie.cn/thread-243089-1-1.html[加壳方式]: SE壳[使用工具]: OD+WinHex+CFF Explorer[作者声明]: 只是感兴趣,没有其他目的.失误之处敬请诸位大侠赐教!思路来自吾爱大牛:Pnmker的教程谢谢!-------------------------

浅入深出之Java集合框架(下)

Java中的集合框架(下) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,哈哈这篇其实也还是基础,惊不惊喜意不意外 ̄▽ ̄ 写文真的好累,懒得写了.. 温馨提醒:建议从(上)开始看哦~ 目 录 浅入深出之Java集合框架(上) 浅入深出之Java集合框架(中)   浅入深出之Java集合框架(下) 前 言 在<浅入深出之Java集合框架(中) >中介绍了Map接口的基本操作.使用的示例是在<浅入深出之Java集合框架(上)>中的模拟学

浅入深出之Java集合框架(上)

Java中的集合框架(上) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,如果已经有java基础的小伙伴可以直接跳到<浅入深出之Java集合框架(下)>. 目录: 浅入深出之Java集合框架(上) 浅入深出之Java集合框架(中)   努力赶制中..关注后更新会提醒哦! 浅入深出之Java集合框架(下) 努力赶制中..关注后更新会提醒哦! 一.集合概述 1)集合的概念 现实生活中的集合:很多事物凑在一起. 数学中的集合:具有共同属性的事物的总体