前言
本文主要讲解vue3中响应式api相关。废话不多说,先上文档。重要一点:响应式api是脱离组件的,区别于option api。
vue3文档:vue3js.cn/docs/guide/…
reactivity api文档:vue3js.cn/docs/api/ba…
以下介绍部分api:分为四个响应式api,四个判断,两个监听,两个转换,一个注意。
理论
四个响应式api
通过他们得到的值全都具有响应式。
reactive
reactive api接收一个plain object,返回一个代理,代理传入的对象。因为是一个代理,所以读取和写入都能收到通知。见下图。
readonly
readonly接收一个plain object或者proxy,返回一个代理。
readonly字面意思我们也知道他是一个只读的,只能读取代理对象中的成员,不能修改。
可以看到当我们修改对象中的属性的时候,控制台报了警告,target is readonly。但是readonly可以接收一个proxy,不能修改他,可以修改这个proxy。
上图中obj2代理了obj1,obj2只读,要修改对象,只能通过obj1,这样有什么用呢?一般在注入数据不希望被修改的时候会用到或者封装一些数据。举个例子,比如一个用户的年龄,暴露出去useAge,setUseAge。这样就可以把一部分共用逻辑抽离出来复用。
ref
ref接收任意值。如果是原始值,返回一个对象,对象中有个value属性,是个访问器,读取设置触发get、set方法。如果是一个对象,调用reactive,返回一个代理。如果本身是一个代理,则直接返回代理。
读取的话:
对于原始数据类型:xx.value。
对于引用类型:xx.value.属性。
computed
computed接收一个函数,只在依赖变化时运行,若多次调用,不会重复运行(有缓存机制)。
总结:
相同点:
四个api都返回响应式数据。
不同点:
reactive和readonly返回的是Proxy,ref和computed返回的是ref object。对于proxy,读取时直接读取属性。对于ref object,读取时使用.value.属性。
我们平时写代码的时候,
想让一个对象具有响应式,使用reactive和ref。
想让一个对象的所有属性只读,使用readonly。
想让一个非对象变成响应式,使用ref。
根据**已有响应式数据**得到一个新的响应式数据,使用computed。
一个小demo:看懂就基本掌握了
四个判断
isProxy:判断是否reactive和readonly创建的。
isReactive:判断是否reactive创建的。
isReadonly:判断是否readonly。
isRef:判断是否是个ref object。
两个监听
先看示例。
watchEffect:
watch:
watchEffect:
watchEffect特点:返回一个函数;一开始会运行一次;自动收集响应式数据依赖,依赖改变自动运行;多次改变放到微队列一次执行完。
另一个特点,可以像计时器一样有个ID,调用ID停止监听。
watchEffect:
watchEffect特点:返回一个函数;一开始会运行一次;自动收集响应式数据依赖,依赖改变自动运行;多次改变放到微队列一次执行完。
另一个特点,可以像计时器一样有个ID,调用ID停止监听。
watch:
和vue2的watch使用基本一致。可以监听多个数据,监听的数据对于reactive数据,返回一个函数(改变时运行),对于ref数据,可以返回函数,也可以是ref(不要直接写成.value,.value是一个具体的数据类型(收集不到依赖),ref是一个对象),多次改变放到微队列一次执行完。
总结:
一般我们选择watchEffect,自动收集依赖。但是下述三种情形我们选择使用watch:
1、不希望函数一开始就执行;
2、数据改变时,需要参考旧值;
3、监听只是为了别的操作,比如打个日志,数据变动,但并不会用到数据;
一个小demo:看懂就基本掌握了
对于事件循环不明白的建议参考:异步操作参考问题(juejin.cn/post/705710…)
两个转换
unref:其实就是 isRef(val) ? val.value : val; //当不确定传入的是proxy还是ref object的时候。
toRefs:把一个对象的所有属性转成ref object,返回一个plain object;
{
a: {value: ...},
b: {value: ...}
}
一个注意
特别注意解构的使用。不当使用会使数据丢失响应式。所以一般返回时使用toRefs()使整个响应式对象的所有属性转换为ref object,然后包装到一个plain object中返回。