本篇文章带大家学习vue,深入了解vue中响应式原理,希望对大家有所帮助!
以此文纪念将要逝去的响应式语法糖
废话不多说,直接进入正题,响应式在日常开发中的应用是很常见的,这里举个简单的例子:
let a=3let b=a*10console.log(b)//30a=4console.log(b)//40
这时候我们想让b=4*10,这样显然是不行的,即使我们在前面加上个var也只会发生变量提升,我们所给的值并不会提升。
而这个时候,响应式的作用就体现出来了:
import { reactive } from 'vue'let state = reactive({ a: 3 })let b = computed(() => state.a * 10)console.log(b.value) // 30state.a = 4console.log(b.value) // 40
只需要一个简单的响应式api便可实现跟踪变化的效果。【相关推荐:vuejs视频教程、web前端开发】
分析一下reactive事实上,vue3的reactive的本质上就是一个发布订阅模式
通过创建依赖图来跟踪数据的依赖关系。依赖图是一个图形,它描述了哪些数据是依赖于哪些数据的。当数据发生变化时,vue 3 的 reactive 系统会自动触发视图的更新。这是因为它在依赖图中跟踪了数据变化,并通过将其与视图的更新关联起来来实现的
这里我列出尤大在vue master里演示的代码做个简单的示例:
class dep{ constructor(value){ this.subscribers=new set() this._value=value } get value(){ this.depend() return this._value } set value(newvalue){ this._value=newvalue this.notify() } depend(){ if(activeeffect){ this.subscribers.add(activeeffect) } } notify(){ this.subscribers.foreach(effect=>{ effect() }) }}
我们来分析一下这段代码:
定义一个subscribe属性,作为一个订阅者列表,用来存储所有的订阅者信息depend函数用来管理依赖关系,即该订阅者所依赖的该变量notify函数便是作为通知所有订阅者该变量的值已经发生变化当变量的值发生变化的时候,它便可以自动的通知所有的订阅者进行更新了
vue2的object.defineproperty事实上,在vue2时期,响应式的都是交给object.defineproperty来实现的,但在vue3当中切换成了proxy,我们等下来结合实际代码来看原因;我们先来看看vue2是如何实现的:
function reactive(raw){ object.keys(raw).foreach(ket=>{ const dep=new dep() let value=raw[key] object.definproperty(raw,key,{ get(){ dep.depend() return value }, //当属性发生 set(newvalue){ value=newvalue dep.notify() } }) }) //这时候返回的原始对象已经具有响应性 return raw}
这样一个简单的响应式api就实现了
但这里缺点也就很明显了:在 vue 2.x 中,被传入的对象会直接被 vue.observable 变更 而在vue3当中,则是会返回一个可响应的代理,而对源对象直接进行变更仍然是不可响应的
这就导致了:
当我们添加或者删除对象的属性时,vue2的响应式是无法检测的,由于 vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 vue 将它转换为响应式的无法检测数组的下标和长度的变化当然,这个属于历史局限了,当时es5也就只能选择object.definproperty,但在了es6版本,便多了proxy,这时候vue的响应式便得到了升级
vue3的proxyvue3采用proxy来监控数据的变化,相较于vue2来说,不仅解决了上述的问题,还有这些优势:
无需再使用vue.$set来触发响应式,这让代码看上去能过更加简介全方位的数组变化检测,消除vue2中无效边界情况减少了vue3中书写响应式的代码量,这让我们的开发更加方便让我们来看看实际代码是什么样子的:
const reactivehandles={ get(target,key,receiver){ const dep=getdep(target,key) dep.depend() return reflect.get(target,key,receiver) }, set(target,key,value,receiver){ const dep=getdep(target,key) const result=reflect.set(target,key,value,receiver) dep.notify() return result }}
通过对对象进行收集依赖来实现响应式的方式也便是vue3响应式的精髓
ref在官方文档有句话:reactive() 的种种限制归根结底是因为 javascript 没有可以作用于所有值类型的 “引用” 机制,而reactive的限制便是:
只能处理可被观测的数据结构,如数组和对象;而不可观测的数据结构,如原始数据类型就无法被其监测只能处理定义在它所在组件的数据,不能处理全局变量而这个时候就需要ref来登场了,ref便是针对基本数据类型而诞生的,弥补了reactive的缺陷,简单的来说,ref更加适合简单的单个可变值(不过实际开发大多数时候都是ref一把梭哈哈哈
这里顺便提一下,响应式语法糖的提案被取消了还是蛮可惜的
(学习视频分享:vuejs入门教程、编程基础视频)
以上就是一文详解vue中响应式原理的详细内容。