概述

React并不是一个MVVM框架,其实它连一个框架都算不上,它只是一个库,但是react生态系统中的flux却是一个MVVM框架,所以我研究了一下flux官方实现中的“双向绑定”,并记录下来供以后开发时参考,相信对其他人也有用。

参考资料:

如何监听 js 中变量的变化?

Flux For Beginners

数据双向绑定的分析和简单实现

The ReactJS Controller View Pattern

Controller View

React的核心思想是Controller View设计模式:顶层组件具有所有的state,并把它们作为props向下传递给子组件。

这样的好处有:

  1. 如果要增加一个相同的子组件,直接增加即可。
  2. 如果有url参数解析,直接从父组件得到,不需要单独重复处理。
  3. 与可变的state相比,静态的props更加容易理解和预测。
  4. 方便测试。(只需传入props即可)

这种设计模式实现的数据流动其实是一种单向流动,即从父组件流向子组件。如果子组件要向父组件传递数据,那么只能通过父组件把回调函数作为props传递给子组件,然后子组件通过调用这个回调函数来传递数据给父组件,这样就实现了父组件和子组件之间数据的双向流动

然而,这个设计模式有一个缺点,就是需要一层一层地向下传递数据,如果层级很多的话,就特别麻烦,每个子组件接收的props不全是它需要的数据,还有很多它并不需要但是它的子组件需要的数据。在这种情况下就需要用到flux。

注意:如果层级很少的话,就不建议使用flux或redux。

flux的双向绑定

我们知道数据的双向绑定是指:

  1. view层的用户修改界面数据,model层的数据也会被修改。这个可以通过浏览器自带的事件响应来解决。
  2. model层的数据修改会同步到view层画面的变化。这个时候就涉及到2个方面,一个是model层的数据会渲染到view层,通过react的数据流动即可实现;另一个是model层的数据变化会引起注意,在这个方面,angular是通过脏检测实现的,vue是通过es5的getter和setter以及Object.defineProperty方法(数据劫持)实现的,那么flux是怎么实现的呢?

flux是通过和浏览器类似的事件响应实现,通过事件监听数据的变化,如果有变化,就引发一个change事件,从而实现同步数据到view层。

事件监听其实是一种观察者模式,下面我们来具体讨论一下事件监听的实现。这个实现需要解决下列问题(以change事件为比方):

  1. 数据具有绑定change事件的方法。
  2. 数据在change事件发生的时候能够调用绑定的回调函数。
  3. 数据在改变的时候能够触发change事件。

首先我们要引入MicroEvent.js,这个库只有一页代码,我选取其中重要的部分来讲解:

var MicroEvent  = function(){};
MicroEvent.prototype = {
bind : function(event, fct){
this._events = this._events || {};
this._events[event] = this._events[event] || [];
this._events[event].push(fct);
},
unbind : function(event, fct){
this._events = this._events || {};
if( event in this._events === false ) return;
this._events[event].splice(this._events[event].indexOf(fct), 1);
},
trigger : function(event /* , args... */){
this._events = this._events || {};
if( event in this._events === false ) return;
for(var i = 0; i < this._events[event].length; i++){
this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1));
}
}
};

MicroEvent对象的实例有bind,unbind和trigger方法,分别对应绑定自定义事件,解绑,触发事件。这样通过object.asign方法就能把这些方法“给”数据。这就解决了第一个问题。

然后数据在通过bind绑定自定义事件及回调函数之后,可以通过trigger触发自定义事件并且依次执行绑定在事件上的回调函数。这就解决了第二个问题。

接下来是第三个问题,我们怎么在数据改变的时候触发事件???

在这一点上,vue是通过es5的getter和setter以及Object.defineProperty方法,通过重写setter函数,并在里面写上trigger事件的代码,实现数据在改变的时候能自动调用trigger方法,从而实现了触发事件。

但是flux用的并不是这种方法!!!我们先来看一下vue里面实现事件响应的过程,数据的任何改动都会触发Object.defineProperty绑定的setter方法,从而实现调用trigger方法。所以如果我们只定义具体的改动呢?这样是不是可以不用Object.defineProperty方法?

这就是flux的实现,我们并不是直接修改数据,而是通过定义具体的动作,通过这个动作修改数据。

AppDispatcher.dispatch({
actionName: 'new-item',
newItem: { name: 'Marco' } // example data
});

而这个动作在被调用的时候会自动触发trigger函数,从而实现事件响应!!!

这就是为什么flux里面要分为Actions,Dispatcher,Store的原因。我们并不是直接修改数据,而是通过一个中间层Actions修改数据,这样这个中间层在被调用的时候会触发trigger函数,实现事件响应!

其它

值得一提的是,node自带Events库,通过这个库也能够实现与上面的事件响应。但是MicroEvent.js适用性更广,它还能够适用于客户端。

另外,es6定义了新的双向绑定机制——Proxy

Proxy就是对象代理,类似上面的中间层actions,它可以给一个对象绑定一个代理对象,通过这个代理对象来代理原对象的各种行为。

var p = new Proxy(target, handler);

let a = new Proxy({}, {
set: function(obj, prop, value) {
obj[prop] = value; if (prop === 'zhihu') {
console.log("set " + prop + ": " + obj[prop]);
} return true;
}
}); a.zhihu = 100;

当然,Proxy的能力远不止此,还可以实现代理转发等等。

至于兼容性,Proxy的大部分方法都被各大浏览器实现了,只有少数几个方法没有被实现。具体可以看这里:MDN Proxy

React中的“双向绑定”的更多相关文章

  1. AngularJS中数据双向绑定(two-way data-binding)

    1.切换工作目录 git checkout step-4 #切换分支,切换到第4步 npm start #启动项目 2.代码 app/index.html Search: <input ng-m ...

  2. vue中的双向绑定

    概述 今天对双向绑定感兴趣了,于是去查了下相关文章,发现有用脏检查的(angular.js),有用发布者-订阅者模式的(JQuery),也有用Object.defineProperty的(vue),其 ...

  3. react 实现数据双向绑定

    好久没有更新了 只是都写在有道笔记中 今天整理下 一些基础的 大神勿喷 一个基础的不能再基础的数据双向绑定 因为react不同于vue 没有v-model指令 所以怎么实现呢? import Reac ...

  4. vue中数据双向绑定注意点

    最近一个vue和element的项目中遇到了一个问题: 动态生成的对象进行双向绑定是失败 直接贴代码: <el-form :model="addClass" :rules=& ...

  5. vue中数据双向绑定的实现原理

    vue中最常见的属v-model这个数据双向绑定了,很好奇它是如何实现的呢?尝试着用原生的JS去实现一下. 首先大致学习了解下Object.defineProperty()这个东东吧! * Objec ...

  6. javascript中的双向绑定

    阅读目录 一:发布订阅模式实现数据双向绑定 二:使用Object.defineProperty 来实现简单的双向绑定. 前言: 双向数据绑定的含义:可以将对象的属性绑定到UI,具体的说,我们有一个对象 ...

  7. wp中的双向绑定

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; usin ...

  8. 利用JS实现vue中的双向绑定

    Vue 已经是主流框架了 它的好处也不用多说,都已经是大家公认的了 那我们就来理解一下Vue的单向数据绑定和双向数据绑定 然后再使用JS来实现Vue的双向数据绑定 单向数据绑定 指的是我们先把模板写好 ...

  9. AngularJS学习--- AngularJS中数据双向绑定(two-way data-binding) orderBy step4

    1.切换工作目录 git checkout step- #切换分支,切换到第4步 npm start #启动项目 2.代码 app/index.html Search: <input ng-mo ...

随机推荐

  1. springboot @Value获取值为空,解决办法

    在spring中,常常使用 @Value("${property}") 从application.properties中取值,需要注意两点 使用 @Value 的类不能使用 new ...

  2. python 函数的名称空间及作用域

    一:名称空间 1:什么是名称空间: 名称空间即:储存名字与值的内存地址关联关系的空间 2.名称空间的分类: 内置名称空间:存储器自带的一些名称与值的对应关系,如:print,len,max等; 生命周 ...

  3. SpringCloud详解

    来源于纯洁的微笑 http://www.ityouknow.com/spring-cloud.html

  4. 微信小程序星星评价

    https://www.jianshu.com/p/4d7359dfa040

  5. WM-结汇

    PI发给客户以后, 客户打过来定金之后. 把PI的 P单词去掉,改为只剩invoice, 再把PI改成一份contract为标题的文件,两份文件都是要自己和客户的签字的. 然后需要用这两份文件进行结汇 ...

  6. extern和include的作用

    首先要搞清楚的是.h头文件中都是一些声明性的语句,是不分配内存的,所以头文件中有对函数的声明,有define语句,有没有实例化的结构体定义,但是没有对变量的定义(比如 int a),有的只是对外变量的 ...

  7. python note 01 计算机基础与变量

    1.计算机基础. 2.python历史. 宏观上:python2 与 python3 区别: python2 源码不标准,混乱,重复代码太多, python3 统一 标准,去除重复代码. 3.pyth ...

  8. python深入理解类和对象

    1,鸭子类型和多态 当看到一只鸟走起来像鸭子,游泳起来像鸭子,叫起来也像鸭子,那这只鸟就是鸭子 是不是比较混乱,看个例子: # -*- coding:UTF-8 -*- __autor__ = 'zh ...

  9. mysql解压缩版安装方法以及mysql无法启动1067错误

    https://jingyan.baidu.com/article/f3ad7d0ffc061a09c3345bf0.html我下载的版本号是5.6.421.解压到C:\Program Files\M ...

  10. ORM初识和数据库操作

    ORM简介 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术.简单的说,ORM是通过使用描述对象和数据库之 ...