Open switer opened 9 years ago
React中触发 UI re-render 有两个方法 setProps, setState, setProps 在官方定义上是给外部 JS 调用的,而 setState 是内部逻辑使用的,两个调用方式一致:
component.setProps({ name: 'switer' }) component.setState({ name: 'switer' })
在此以 setState 为例。 React 的组件内的所有状态都挂载在 this.state 对象下, setState 其实就是 this.state 的一个 setter 。观摩下 setState 的使用:
this.state
setter
// 该方法获取初始 state 对象 getInitialState: function () { return { name: 'switer' } }, // 初始渲染后做些操作 componentDidMount: function () { // 我想将 name: switer --> name: guankaishe var state = this.state state.name = 'switer' this.setState(state) }
使用方式有点残暴,all right?想要方便开发,你可以自定义一个 mixin,根据 keypath 来更新 state:
mixins: [{ sst: function (keypath, value) { var state = this.state updateValueByKeypath(state, keypath, value) this.setState(state) } }], componentDidMount: function () { // 我想将 name: switer --> name: guankaishe this.sst('name', 'switer') }
ES5 的 Object.definePropety 方法提供了定义对象的 getter/setter 方法。 由于在 setter 被调用的时候会触发 change 事件,所以每个对象都是 observable 的。
Object.definePropety
vue.js 中在定义一个类的时候,有个 data 选项,该选项就是该类下的所有 属性/数据/状态 的挂载对象。
data
new Vue({ data: { props: {}, ... state: {}, ... dataset: {} ... } })
Vue 会在 init/created 阶段获取 data 对象的属性的 keypath 并定义 setter, keypath 是用以 DOM 解析阶段绑定数据。如果属性值为 Array/Object 类型,进行递归遍历操作。
init/created
Array/Object 类型
data: { obj: { // keypath: obj name: 'switer' // keypath: obj.name }, arr: [{ // keypath: arr name: 'switer' // arr[0].name }, 'guankaishe' // arr[1] ] }
同时,data 与每一个 Array/Object 类型的属性,都会添加一个事件分发器对象属性 "__EventEmitter__",当 setter 触发 change 事件后,通过该分发器告诉对象的订阅者处理方法(会有相应的页面渲染方法)。
"__EventEmitter__"
Notice: Vue.js 在 0.11.x 后将 "__EventEmitter__" 修改为 "__ob__" Notice: Array/Object 类型数据使用新赋值引用,会抹除EventEmitter,导致重新的解析操作。且由于 Vue.js 的 diff 算法不会进行深度遍历,易产生性能问题。
"__ob__"
Angular 还没有相关的实践资料,相关了解都是网站查资料所得: how-angularjs-implements-dirty-checking . 个人认为,Angular 没有使用 Change-method 的理由是,显性的 setter 方法调用方式影响开发效率, 使用 defineProperty 定义 setter 是最方便的方式,但 IE* 浏览器不支持该方法。 angular 使用交换性能换来兼容性与易用性的实现方式 -- dirty checking.
性能
兼容性
易用性
$scope.name = 'switer' $scope.$watch('name', function (nv, ov) { console.llg('name value change to', nv) })
由上面代码可以看到,直接通过赋值运行 = 可以触发 $watch 的回调(也会有 UI re-redner)。 Angular 没有使用 defineProperty 来定义 setter ,在 setter 调用的时候触发 change 事件, 而是使用 Polling loop 来定时轮询数据是否变脏。数据变脏(change)的时候,就触发相对应的 change 回调方法与及更新 UI。所以称之为 dirty-checking。
=
Polling loop
The implementation of change listener of data-binding
Change-method -- react
React中触发 UI re-render 有两个方法 setProps, setState, setProps 在官方定义上是给外部 JS 调用的,而 setState 是内部逻辑使用的,两个调用方式一致:
在此以 setState 为例。 React 的组件内的所有状态都挂载在
this.state
对象下, setState 其实就是 this.state 的一个setter
。观摩下 setState 的使用:使用方式有点残暴,all right?想要方便开发,你可以自定义一个 mixin,根据 keypath 来更新 state:
ES5 defineProperty -- vue.js
ES5 的
Object.definePropety
方法提供了定义对象的 getter/setter 方法。 由于在 setter 被调用的时候会触发 change 事件,所以每个对象都是 observable 的。vue.js 中在定义一个类的时候,有个
data
选项,该选项就是该类下的所有 属性/数据/状态 的挂载对象。Vue 会在
init/created
阶段获取 data 对象的属性的 keypath 并定义 setter, keypath 是用以 DOM 解析阶段绑定数据。如果属性值为Array/Object 类型
,进行递归遍历操作。同时,data 与每一个 Array/Object 类型的属性,都会添加一个事件分发器对象属性
"__EventEmitter__"
,当 setter 触发 change 事件后,通过该分发器告诉对象的订阅者处理方法(会有相应的页面渲染方法)。Notice: Vue.js 在 0.11.x 后将
"__EventEmitter__"
修改为"__ob__"
Notice: Array/Object 类型数据使用新赋值引用,会抹除EventEmitter,导致重新的解析操作。且由于 Vue.js 的 diff 算法不会进行深度遍历,易产生性能问题。Dirty checking -- angular
Angular 还没有相关的实践资料,相关了解都是网站查资料所得: how-angularjs-implements-dirty-checking . 个人认为,Angular 没有使用 Change-method 的理由是,显性的 setter 方法调用方式影响开发效率, 使用 defineProperty 定义 setter 是最方便的方式,但 IE* 浏览器不支持该方法。 angular 使用交换
性能
换来兼容性
与易用性
的实现方式 -- dirty checking.由上面代码可以看到,直接通过赋值运行
=
可以触发 $watch 的回调(也会有 UI re-redner)。 Angular 没有使用 defineProperty 来定义 setter ,在 setter 调用的时候触发 change 事件, 而是使用Polling loop
来定时轮询数据是否变脏。数据变脏(change)的时候,就触发相对应的 change 回调方法与及更新 UI。所以称之为 dirty-checking。conclusion