vue3之Reactivity Api

202 阅读4分钟

前言

本文主要讲解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,返回一个代理,代理传入的对象。因为是一个代理,所以读取和写入都能收到通知。见下图。

image.png

image.png

readonly

readonly接收一个plain object或者proxy,返回一个代理。

readonly字面意思我们也知道他是一个只读的,只能读取代理对象中的成员,不能修改。

可以看到当我们修改对象中的属性的时候,控制台报了警告,target is readonly。但是readonly可以接收一个proxy,不能修改他,可以修改这个proxy。

image.png

image.png 上图中obj2代理了obj1,obj2只读,要修改对象,只能通过obj1,这样有什么用呢?一般在注入数据不希望被修改的时候会用到或者封装一些数据。举个例子,比如一个用户的年龄,暴露出去useAge,setUseAge。这样就可以把一部分共用逻辑抽离出来复用。

image.png

image.png ref

ref接收任意值。如果是原始值,返回一个对象,对象中有个value属性,是个访问器,读取设置触发get、set方法。如果是一个对象,调用reactive,返回一个代理。如果本身是一个代理,则直接返回代理。

读取的话:
		对于原始数据类型:xx.value。
		对于引用类型:xx.value.属性。

image.png

image.png computed

computed接收一个函数,只在依赖变化时运行,若多次调用,不会重复运行(有缓存机制)。

image.png

image.png

总结:
    相同点:
	四个api都返回响应式数据。
    不同点:
    	reactive和readonly返回的是Proxy,ref和computed返回的是ref object。对于proxy,读取时直接读取属性。对于ref object,读取时使用.value.属性。
我们平时写代码的时候,
想让一个对象具有响应式,使用reactive和ref。
想让一个对象的所有属性只读,使用readonly。
想让一个非对象变成响应式,使用ref。
根据**已有响应式数据**得到一个新的响应式数据,使用computed。

一个小demo:看懂就基本掌握了

image.png

image.png

四个判断

isProxy:判断是否reactive和readonly创建的。

isReactive:判断是否reactive创建的。

isReadonly:判断是否readonly。

isRef:判断是否是个ref object。

两个监听

先看示例。

watchEffect:

image.png

image.png watch:

image.png

image.png watchEffect:

watchEffect特点:返回一个函数;一开始会运行一次;自动收集响应式数据依赖,依赖改变自动运行;多次改变放到微队列一次执行完。

另一个特点,可以像计时器一样有个ID,调用ID停止监听。

watchEffect:

watchEffect特点:返回一个函数;一开始会运行一次;自动收集响应式数据依赖,依赖改变自动运行;多次改变放到微队列一次执行完。

另一个特点,可以像计时器一样有个ID,调用ID停止监听。

watch:

和vue2的watch使用基本一致。可以监听多个数据,监听的数据对于reactive数据,返回一个函数(改变时运行),对于ref数据,可以返回函数,也可以是ref(不要直接写成.value,.value是一个具体的数据类型(收集不到依赖),ref是一个对象),多次改变放到微队列一次执行完。

image.png

image.png

总结:
		一般我们选择watchEffect,自动收集依赖。但是下述三种情形我们选择使用watch:
    1、不希望函数一开始就执行;
    2、数据改变时,需要参考旧值;
    3、监听只是为了别的操作,比如打个日志,数据变动,但并不会用到数据;

一个小demo:看懂就基本掌握了

image.png

image.png 对于事件循环不明白的建议参考:异步操作参考问题(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中返回。