概述

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. ps命令详解

    1.简介: ps 命令有两种不同的语法风格 —— BSD 与 UNIX 两种风格.新手常常对这两种形式产生误解,因此我们有必要在这里作一个简单的说明: ps aux 与 ps -aux 是不同的,例如 ...

  2. df命令详解

    1.简介: df命令作用是列出文件系统的整体磁盘空间使用情况.可以用来查看磁盘已被使用多少空间和还剩余多少空间. df命令显示系统中包含每个文件名参数的磁盘使用情况,如果没有文件名参数,则显示所有当前 ...

  3. ceph常用运维技巧总结1

    格式 json 数据增强可读性 --format json-pretty -f json-pretty ceph quorum_status -f json-pretty ceph mon_statu ...

  4. R语言-简单模型画图

    1.回归拟合 > plot(mtcars$mpg~mtcars$disp) > lmfit<-lm(mtcars$mpg~mtcars$disp) #线性回归模型 > abli ...

  5. Unity中的点击,长按,划动

    public void GetClickType() { if(Input.GetMouseButtonDown(0)) { if(isGetBeginPos) { beginPosition = I ...

  6. 网络文件系统NFS

    NFS介绍 什么是NFS? NFS是Network File System的缩写,即网络文件系统.它的主要功能是通过网络(一般是局域网)让不同的主机系统之间可以共享文件或目录.NFS客户端(一般为应用 ...

  7. js监控鼠标滚动事件

    //滚动动画 windowAddMouseWheel(); function windowAddMouseWheel() { var scrollFunc = function (e) { e = e ...

  8. 使用setx 命令添加环境变量(Windows)

    背景 用GUI的方法可能添加环境变量可能会比较麻烦,为此可采用命令行操作的方式. 步骤 以管理员身份运行 cmd 输入 setx /M "%path%" "%path%[ ...

  9. 如何访问dashed filename

    第一关:boJ9jbbUNNfktd78OOpsqOltutMc3MY1 第二关:CV1DtqXWVFXTvM2F0k09SHz0YwRINYA9 cat <- 第三关:如何访问spaces i ...

  10. centos7切换图像界面和dos界面

    在图形界面使用 ctrl+alt+F2切换到dos界面 dos界面 ctrl+alt+F2切换回图形界面 在命令上 输入 init 3 命令 切换到dos界面 输入 init 5命令 切换到图形界面 ...