来自 Web前端 2020-05-07 05:42 的文章
当前位置: 网上澳门金莎娱乐 > Web前端 > 正文

Nautil 中使用双向数据绑定网上澳门金莎娱乐

const $state = createTwoWayBinding(state)Input $value={$state.value} /

双向绑定

但是,如果你想让一个普通对象也可以实现响应式,你可以利用第二个参数:

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

组件内直接使用 this.attrs.age ++ 修改外部传来的属性,目标是反写外部数据外部组件在往子组件传递双向绑定属性时,需要传入一个特定结构

新的思维方式

Input value={state.value} onChange={e = state.value = e.target.value} /
$value={[state.value,value= state.value=value]}

这样写可能更容易理解一些。

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

import { Component, Store } from 'nautil'import { createTwoWayBinding } from 'nautil/utils'import { initialize, pipe, observe } from 'nautil/operators'import { Section, Text, Input } from 'nautil/components'export class OneComponet extends Component { static props = { store: Store, } render() { const { store } = this.attrs const { state } = store const $state = createTwoWayBinding(state) // 创建一个可用于双向绑定的宿主对象 return ( Section Textname: {state.name}/Text Input $value={$state.name} / /Section ) }}export default pipe([ initialize('store', Store, { name: 'tomy' }), observe('store'),])(OneComponent)

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

小结

import { Store } from 'nautil'const store = new Store({ some: 123,})
const { state } = this // react 的 state 本质上是一个普通对象const $state = createTwoWayBinding(state, ([state, keyPath, value], [target, key]) = { this.setState({ [key]: value })})Input $value={$state.name} /

也可以这样写(标准写法):

一个双向绑定的语法,实际上是一个数据绑定和一个事件响应的结合体。不过 vue 有一个优势,它是基于模板解析的,所以写法上非常有优势。而 react 如果要依靠编译的话,非常不稳定,因为不知道其他人打算怎么用。最后,我找到一种特别的语法,用来表达双向绑定这种数据传递方式。

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

从原理上将,nautil 中的双向绑定基于一个特定结构。在这个特定结构中,包含了值本身,和一个值改变时的回调函数,当组件内部的该值发生变化时,这个回调函数会被执行,更新界面的动作,在回调函数中被执行。而这个特定结构,被 createTwoWayBinding 抹平了结构在视觉上的差异。它的原始结构实际上是:

本文主要介绍了为什么要在 Nautil 中实现双向绑定,怎么实现,以及如何使用的问题。虽然本文主要是介绍 Nautil 中的双向数据绑定,但是也讨论了 react, vue, angular 的一些数据状态管理的东西

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

利用双向绑定

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

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

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

Input, Textarea 等表单组件都有双向绑定功能。但是,假如现在你自己想写一个组件,使用双向绑定功能,你需要怎么写?其实很简单,只需要直接操作 this.attrs 上的属性即可:

我们先来看下一个实现的效果:

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

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

createTwoWayBinding

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

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

之所以state.value = value可以更新界面的渲染,是因为我们通过 observe 指令观察了 store 的变化,从而在外层就让界面可以根据 store 的变化而更新。

该函数用于基于传入的对象,创建一个用于双向绑定的对象。它的传入参数是任意的,但是我推荐使用 store 或 model 的 state,这样就不用自己构造第二个参数。

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

Input $value={state} /

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

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

目的上,createTwoWayBinding 最终是为双向绑定服务的,所以不应该用它所创建的对象去读取值。

对于组件本身而言,如何利用双向绑定完成一些事情呢?我们来看Input 组件的源码:

import { Component } from 'nautil'import { Button } from 'nautil/components'export class Some extends Component { static props = { $age: Number, } render() { return ( Button onHint={() = this.attrs.age ++}grow/Button ) }}
export class Input extends Component { render() { const { type, placeholder, value, ...rest } = this.attrs const onChange = (e) = { const value = e.target.value this.attrs.value = value // 主要是这一句 this.onChange$.next(e) } return input {...rest} type={type} placeholder={placeholder} value={value} onChange={onChange} onFocus={e = this.onFocus$.next(e)} onBlur={e = this.onBlur$.next(e)} onSelect={e = this.onSelect$.next(e)} className={this.className} style={this.style} / }}

对于 Input 组件而言,中间比普通 react 组件多了一句this.attrs.value = value,这句话利用了双向绑定特殊结构的第二个值,进行值的回传和反写。也就是说,在 nautil 中,双向绑定具有兼容性,你可以这样写:

当然,如果你知道 nautil 里面的内置规则,甚至还可以这样写:

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

inputtype="text"v-model="name"/

上面的代码利用了比较多的东西,例如 nautil 中的 Store 和指令。但单纯双向绑定这个点,你只需要注意 Input 组件的 $value 属性。在 nauti 中,$开头的属性表示双向绑定属性,它的值必须是一个特定结构,而非普通值。

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

inputtype="text":value="name"@input="name = $event.target.value"/

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

Input $value={[state.value, value = state.value = value]}

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

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

时间: 2019-09-02阅读: 80标签: 数据绑定原文:

现有状态管理的问题

这样的写法比较严格,要求外部传入的时候,必须传入$age这个属性,而不允许传入 age 属性。为了兼容,你可以学习 Input 组件的做法,在 onHint 的回调函数中,增加一个回调函数的调用。

需要注意,this.attrs.age ++这个语句,不会真的修改 this.attrs.age 的值,这个修改动作会被拦截,它只是在编程上顺延了 js 语法,但实际上,它的效果是调用双向绑定特定结构的第二个参数,至于 this.attrs.age 的值是否真的变化,取决于双向绑定特定结构第二个参数是否修改外部传入的 age 值发生变化。

或者也可以利用前面提到的 createTwoWayBinding 函数(推荐用法):

本文由网上澳门金莎娱乐发布于Web前端,转载请注明出处:Nautil 中使用双向数据绑定网上澳门金莎娱乐

关键词: