Nautil 中使用双向数据绑定的实现

虽然是基于 react 的框架,但是在 nautil 中可以使用双向数据绑定,这得益于基于观察者模式的开发思路。在 react 中使用双向绑定并非没有需求,react 严格的单向数据流,严重影响了开发者的发挥空间,特别是在表单组件的使用中,很容易陷入回调地狱,即使 redux 也无法避免。

现有状态管理的问题

我们都知道,react 是单向数据流的,数据只能从外部通过 props 传入,再通过 props 上面传入的回调函数再传出去,直接修改 props 或者上面的对象,不会带来界面的更新,而且会导致数据不可预期。

基于这种单向数据流的 flux 思想,redux 还遵循了函数式编程的规范,保证了数据的干净。同时,它提供了自顶向下的分发机制,修改 redux store 中的数据,会触发所有connected 的组件。而触发过程是,调用 connected 组件 props.dispatch 方法。

虽然单向数据流的方式保证了数据流干净,但 redux 的编程方式太复杂了。它不仅增加了数据构造本身的逻辑代码,而且 action 代码也是分散的,当你需要进行修改时,有的时候会在好几个文件之间转晕。虽然有很多优化 redux 样板代码的库,但受限于它的编程思想,仍然不好在项目中节省更多时间。

新的思维方式

出于节省更多时间成本的目的,我在开发 nautil 中没有使用 flux 那一套,而是另辟蹊径,做了很像 mobx 但又更简单的事。

我们来看一下如何在 nautil 中创建一个 store:

import { Store } from 'nautil' const store = new Store({ some: 123, })

这样我们就创建了一个 store,非常简单,只传入了默认值。而没有各种 reducer 的样板代码。

Store 实例是一个可观察的对象,通过 watch 方法,可以监听 store 中数据的变化。但凡能监听到数据变化,我们就可以在数据变化时,更新界面渲染。所以,在 nautil 中,观察者模式是核心思想,是实现 nautil 中各种响应式效果的前提条件。

如果你用过 vue 的话,你一定喜欢 vue 中操作数据的方式。在 vue 中要将输出框组件和数据绑定非常容易:

<input type="text" v-model="name" />

当用户在输入框中输入内容时,this.name 也会随之变化。而由于 vue 的响应式是自主绑定的,this.name 发生变化的同时,也会触发 vue 内部对整个组件的重新渲染机制。这种将数据映射到视图,再由视图重新映射会数据的编程方式,在 angular 1.x 中随处可见。

在 angular 中,通过 ng-click 等事件绑定,或者控制器中调用 $http 实现数据请求,在响应结束的时候,都会自动触发 angular 内部的 digest,并通过脏检查机制,从顶至底的去完成界面重新渲染,由于脏检查的特质,根本不需要 react 那种要求数据是 immutable 的,即使原始数据被修改,新的界面也会被按照新的数据进行渲染。

我并不是说 angular 这种直接修改数据的方式更好,但起码,在面对开发者时,它更直接,更容易理解,更符合编程习惯。

双向绑定

从某些角度讲,vue 是很容易让人费解的。在 vue 的组件里,需要在组件内内置很多状态来控制,这里的状态指通过 data() 绑定到 this 上的各种响应式属性。在组件内部,修改 this.name 可以触发组件的重新渲染。但是,奇怪的是,vue 不能通过这种方式修改 props 中传入的数据。

这一点很让人费解,对比 react,react 虽然支持组件内 state,但是比较强调组件的可控性,通过 props 来完全掌控 UI 界面的展示,也就是一个状态对应一个 UI 界面。因此,react 提供了函数式组件,这种组件没有自己的 state,这种组件最符合 react 主流思想的口味,而且,整个 react 编程也一以贯之,遵循这种 props 控制一切的理念。

但是,vue 明显更强调 this 上面属性的响应式特性。却又不提供 props 反写的能力,让人百思不解。另一个让人百思不解的是,既然 vue 推崇它的属性响应式特点,为何 vuex 却要像 redux 那样编程?甚至还要分 state, mutaion, action 三种东西,却不继续发挥属性更新形式的响应式编程特点。

Nautil 在这条路上一走到底,将响应式编程发挥到极致。

简单的讲,“双向绑定”是要做到组件内和组件外数据的双向修改,外部修改数据时,组件内部即时响应变化,组件内部修改数据时,外部整个应用的对应部分也随即发生更新。这一点在 angular 1.x 中已经实现了,为何新的框架反而不实现呢?

因此,我要在 nautil 实现的双向绑定方案,更加彻底,更符合开发者想要的方式。

但是,如何在 react 里面实现双向绑定呢?

vue 的 v-model 给了我启示。我们去看 v-model 指令,实质上,它是一个将 v-bind 和 v-on 动作简化的语法糖。

<input type="text" :value="name" @input="name = $event.target.value" />

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/ec2fb050dc3c737384c5d34b19d20d49.html