Vue3 - 响应性API

前言

Vue3.x正式版发布已经快半年了,相信大家也多多少少也用Vue3.x开发过项目。那么,我们今天就整理下Vue3.x中的响应性API。

响应性API

reactive

作用: 创建一个响应式数据。

本质: 传入数据(复杂类型:数组和json对象)包装成一个Proxy对象。如果传入其他对象,默认情况下修改对象,界面不会自动更新,如果想更新,可以通过重新赋值(创建一个新的对象)的方式。

1<template> 2 <div class="reactive"> 3 <button @click="fn">点击</button> 4 <p>{{ state }}</p> 5 <button @click="fn1">点击1</button> 6 <p>{{ timeState }}</p> 7 </div> 8</template> 9 10<script> 11import { reactive } from "vue"; 12export default { 13 name: "Reactive", 14 setup() { 15 let state = reactive({ 16 name: "123", 17 }); 18 function fn() { 19 console.log(state); 20 state.name = "456"; 21 } 22 23 let timeState = reactive({ 24 time: new Date(), 25 }); 26 27 function fn1() { 28 const newTime = new Date(timeState.time.getTime()); 29 newTime.setDate(timeState.time.getDate() + 1); 30 timeState.time = newTime; 31 console.log(timeState.time); 32 } 33 34 return { 35 state, 36 fn, 37 timeState, 38 fn1, 39 }; 40 }, 41}; 42</script> 43 44

ref

作用: 创建一个响应式数据。

本质: (该本质写的不够严谨)针对复杂类型还是reactive。当我们给ref函数传递一个值(一般是简单类型)之后,ref函数底层会自动将ref转换成reactive,即ref(123) => reactive({value:123}),所以修改对应的值必须在后面加上.value

注意点:template标签内不用加.value

1<template> 2 <div> 3 <button @click="fn">点击</button> 4 <p>{{state}}</p> 5 <button @click="fn1">点击1</button> 6 <p>{{arrState}}</p> 7 </div> 8</template> 9 10<script> 11import {ref} from "vue"; 12export default { 13 name:"Ref", 14 setup(){ 15 let state = ref(123); 16 function fn () { 17 state.value = 345; 18 } 19 let arrState = ref([]); 20 function fn1 (){ 21 arrState.value.push("1"); 22 } 23 return { 24 state, 25 fn, 26 arrState, 27 fn1 28 } 29 } 30} 31</script> 32

shallowReactive

作用: 创建一个响应式 proxy,跟踪其自身 property 的响应性,但不执行嵌套对象的深度响应式转换 (暴露原始值)。

本质: 对于嵌套对象不做响应,值跟踪自身的第一层property

1<template> 2 <div> 3 <button @click="fn">点击</button> 4 <button @click="fn1">点击1</button> 5 <p>{{state}}</p> 6 </div> 7</template> 8 9<script> 10import { shallowReactive } from "vue" 11export default { 12 name:"ShallowReactive", 13 setup(){ 14 let state = shallowReactive({ 15 name:"maomin", 16 age:{ 17 number:20 18 } 19 }) 20 function fn(){ 21 state.name = "123"; // 响应性 22 } 23 function fn1(){ 24 state.age.number = 23; // 无响应性 25 } 26 return { 27 state, 28 fn, 29 fn1 30 } 31 } 32} 33</script> 34

shallowRef

作用: 创建一个 ref,它跟踪自己的 .value 更改,但不会使其值成为响应式的。不会将其值转化为Proxy对象。

1<template> 2 <div> 3 <button @click="fn">点击</button> 4 <p>{{ state }}</p> 5 <button @click="fn1">点击1</button> 6 <p>{{ state1 }}</p> 7 </div> 8</template> 9 10<script> 11import { 12 shallowRef, 13 ref, 14 // triggerRef 15} from "vue"; 16export default { 17 name: "ShallowRef", 18 setup() { 19 let state = shallowRef({ 20 name: "maomin", 21 }); 22 let state1 = ref({}); 23 function fn() { 24 state.value.name = "345"; 25 console.log(state.value); // {name: "345"}, 但是UI界面不会变。 26 // triggerRef(state); // 如果想触发UI界面,可以使用它。 27 } 28 function fn1() { 29 state1.value = { 30 name: "123", 31 }; 32 // eslint-disable-next-line no-irregular-whitespace 33 console.log(state1.value); // Proxy {name: "123"} 34 } 35 return { 36 state, 37 fn, 38 state1, 39 fn1, 40 }; 41 }, 42}; 43</script> 44

readonly

作用: 获取一个对象 (响应式或纯对象) 或 ref 并返回原始 proxy 的只读 proxy。只读 proxy 是深层的:访问的任何嵌套 property 也是只读的。

1<template> 2 <div> 3 <button @click="fn">点击</button> 4 <p>{{os}}</p> 5 <p>{{state}}</p> 6 </div> 7</template> 8 9<script> 10import {reactive, readonly} from "vue"; 11export default { 12 name:"Readonly", 13 setup(){ 14 let state = reactive({ 15 name:"maomin", 16 age:{ 17 number:18 18 } 19 }) 20 let os = readonly(state); 21 function fn(){ 22 os.name = "123"; 23 } 24 return{ 25 os, 26 state, 27 fn 28 } 29 } 30} 31</script> 32

shallowReadonly

作用: 创建一个 proxy,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换 (暴露原始值)。

1<template> 2 <div> 3 <button @click="fn">点击</button> 4 <p>{{os}}</p> 5 <p>{{state}}</p> 6 </div> 7</template> 8 9<script> 10import { 11 reactive, 12 shallowReadonly, 13 isReadonly 14 } from "vue"; 15export default { 16 name:"ShallowReadonly", 17 setup(){ 18 let state = reactive({ 19 name:"maomin", 20 age:{ 21 number:18 22 } 23 }) 24 25 let os = shallowReadonly(state); 26 27 function fn(){ 28 console.log(isReadonly(os.name)) //false 29 os.age.number = 20; 30 } 31 return{ 32 state, 33 os, 34 fn, 35 } 36 } 37} 38</script> 39

toRaw

作用: 响应式对象转普通对象。

本质: 返回由reactive或 readonly 方法转换成响应式代理的普通对象。这是一个还原方法,可用于临时读取,访问不会被代理/跟踪,写入时也不会触发更改。不建议一直持有原始对象的引用。

1<template> 2 <div> 3 <button @click="fn">点击</button> 4 <p>{{state}}</p> 5 </div> 6</template> 7 8<script> 9import { reactive, toRaw } from "vue"; 10export default { 11 name:"ToRaw", 12 setup(){ 13 const obj = { 14 name:"maomin" 15 }; 16 let state = reactive(obj); 17 function fn(){ 18 console.log(toRaw(state) === obj); //true 19 let obj1 = toRaw(state); 20 obj1.name = "123"; 21 // eslint-disable-next-line no-irregular-whitespace 22 console.log(state); // Proxy {name: "123"}. 值虽改变,但是页面没有变化。 23 } 24 25 return { 26 state, 27 fn 28 } 29 } 30} 31</script> 32 33

markRaw

作用: 标记一个对象,使其永远不会转换为 proxy。返回对象本身。

1<template> 2 <div> 3 <button @click="fn">点击</button> 4 <p>{{state}}</p> 5 </div> 6</template> 7 8<script> 9import {markRaw,reactive} from "vue" 10export default { 11 name:"MarkRaw", 12 setup(){ 13 let obj = {name:'maomin', age: 20}; 14 obj = markRaw(obj); 15 let state = reactive(obj); 16 function fn(){ 17 state.name = '123'; 18 console.log(state); //这里虽然打印出name:123,但是UI界面不会改变。 19 } 20 return{ 21 state, 22 fn 23 } 24 } 25} 26</script> 27

toRef

如果使用ref,我们修改响应式的数据是不会影响到原始数据的(复制)。如果使用toRef,我们修改响应式的数据是会影响到原始数据的(引用)。

作用: 可以用来为源响应式对象上的 property 新创建一个 ref。然后可以将 ref 传递出去,从而保持对其源 property 的响应式连接。

1<template> 2 <div> 3 <button @click="fn">点击</button> 4 <p>{{state}}</p> 5 <button @click="fn1">点击1</button> 6 <p>{{state1}}</p> 7 </div> 8</template> 9 10<script> 11import {reactive, ref, toRef} from "vue" 12export default { 13 name:"ToRef", 14 setup(){ 15 let obj = {name:"maomin"}; 16 let os = reactive(obj); 17 18 let state = ref(os.name); 19 let state1 = toRef(os,'name'); 20 // ref 21 function fn(){ 22 state.value = "123"; 23 console.log(os); // 原始数据不会发生改变 24 console.log(state); 25 } 26 // toRef 27 function fn1(){ 28 state1.value = "345"; 29 console.log(os); // 原始数据会发生改变 30 console.log(state1); 31 } 32 return { 33 state, 34 fn, 35 state1, 36 fn1 37 } 38 } 39} 40</script> 41

toRefs

作用: 将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的ref

用途: 当从合成函数返回响应式对象时,toRefs 非常有用,这样消费组件就可以在不丢失响应性的情况下对返回的对象进行分解/扩散。

1<template> 2 <div> 3 <button @click="fn">点击</button> 4 <p>{{state}}</p> 5 <button @click="fn1">点击1</button> 6 <p>{{foo}}</p> 7 </div> 8</template> 9 10<script> 11import {reactive, toRefs} from "vue" 12export default { 13 name:"ToRefs", 14 setup(){ 15 let obj = { 16 name:"maomin", 17 age:20 18 } 19 let os = reactive(obj); 20 let state = toRefs(os); 21 22 function fn(){ 23 state.name.value = "123"; 24 os.name = "234"; 25 console.log(os); 26 console.log(state); 27 console.log(state.name.value === os.name); //true 28 } 29 30 const { foo, bar } = useFeatureX(); 31 32 function fn1(){ 33 foo.value = "2"; 34 } 35 return { 36 fn, 37 state, 38 foo, 39 bar, 40 fn1 41 } 42 } 43} 44 45 46function useFeatureX() { 47 const state = reactive({ 48 foo: 1 49 }) 50 // 返回时转换为ref 51 return toRefs(state) 52} 53</script> 54

customRef

作用: 创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数,该函数接收 track 和 trigger 函数作为参数,并应返回一个带有 get 和 set 的对象。

1<template> 2 <div> 3 <button @click="fn">点击</button> 4 <p>{{state}}</p> 5 </div> 6</template> 7 8<script> 9import {customRef} from "vue"; 10 11function myRef(value){ 12 return customRef((track, trigger)=>{ 13 return { 14 get(){ 15 track(); 16 console.log('get',value); 17 return value; 18 }, 19 set(newValue){ 20 console.log('set',newValue); 21 value = newValue; 22 trigger(); 23 } 24 } 25 }) 26} 27export default { 28 name:"CustomRef", 29 setup(){ 30 let state = myRef(18); 31 32 function fn(){ 33 state.value = 19; 34 } 35 return { 36 state, 37 fn 38 } 39 } 40} 41</script> 42

computed

作用: 依赖项变化时,其赋予的值也就相应改变。

注意点: 直接修改computed是不可以的。

1<template> 2 <div> 3 <p>{{state}}</p> 4 <p>{{os}}</p> 5 <button @click="fn">点击</button> 6 </div> 7</template> 8 9<script> 10import {computed,ref} from "vue" 11export default { 12 name: "Computed", 13 setup(){ 14 let state = ref(12); 15 let os = computed(() => state.value + 1); 16 17 function fn(){ 18 state.value = 23; // os的值也会相应改变 19 // os.value = 26; // Write operation failed: computed value is readonly 20 } 21 return{ 22 state, 23 os, 24 fn 25 } 26 } 27} 28</script> 29

watchEffect

作用: 在响应式地跟踪其依赖项时立即运行一个函数,并在更改依赖项时重新运行它。

1<template> 2 <div> 3 <button @click="fn">点击</button> 4 <p>{{state}}</p> 5 <p>{{state1}}</p> 6 <p>{{num}}</p> 7 </div> 8</template> 9 10<script> 11import { reactive, ref, watchEffect } from "vue" 12export default { 13 name:"WatchEffect", 14 setup(){ 15 let state = ref(0); 16 let state1 = reactive({ 17 name:"maomin" 18 }) 19 let num = 1; 20 // 首次运行时会执行它,如果响应依赖项改变时,会重新执行它。 21 watchEffect(()=>{ 22 // console.log(num); 23 console.log(state.value); 24 console.log(state1); 25 }) 26 27 function fn() { 28 state.value = 3; 29 state1.name = "123"; 30 num = 2; 31 } 32 33 return{ 34 fn, 35 state, 36 state1, 37 num 38 } 39 } 40} 41</script> 42

watch

作用: 默认情况下,它也是惰性的——即回调仅在侦听源发生更改时调用。

1<template> 2 <div> 3 <button @click="fn">点击</button> 4 <p>{{state}}</p> 5 <button @click="fn1">点击1</button> 6 <p>{{state1}}</p> 7 </div> 8</template> 9 10<script> 11import {reactive, ref, watch} from "vue" 12export default { 13 name:"Watch", 14 setup(){ 15 16 // reactive 17 let state = reactive({ 18 name:"maomin" 19 }) 20 21 watch( 22 () => state.name, 23 (count) =>{ 24 console.log(count); //123 25 } 26 ) 27 28 function fn() { 29 state.name = "123"; 30 } 31 32 //ref 33 let state1 = ref(1); 34 watch( 35 state1, 36 (count) =>{ 37 console.log(count); //2 38 } 39 ) 40 41 function fn1() { 42 state1.value = 2; 43 } 44 45 return { 46 state, 47 fn, 48 fn1, 49 state1 50 } 51 } 52} 53</script> 54

结语

谢谢阅读,希望没有浪费您的时间。可以结合代码例子自己敲敲代码,响应性API还有很多用处,这里只介绍了九牛一毛,赶快行动起来吧!

点赞
收藏

评论区

加载中...

相关推荐

Vue3.0 高频出现的几道面试题

1.Vue3.0性能提升主要是通过哪几方面体现的?1.响应式系统提升vue2在初始化的时候,对data中的每个属性使用definepropery调用getter和setter使之变为响应式对象。如果属性值为对象,还会递归调用defineproperty使之变为响应式对象。vue3使用proxy对象重写响应式。proxy的性能本来比def

也谈JavaScript浅拷贝和深拷贝

网上关于这个话题,讨论有很多了,根据各路情况我自己整理了一下,最后还是能接近完美的实现深拷贝,欢迎大家讨论。javascript中的对象是引用类型,在复制对象的时候就要考虑是用浅拷贝还是用深拷贝。直接赋值对象是引用类型,如果直接赋值给另外一个对象,那么只是赋值一个引用,实际上两个变量指向的同一个数据对象,如果其中一个对象的属性变更,那么另外一个也会变更。示

Vue 3 深入响应性原理

深入响应性原理终于到了讲解我们Vue的响应式原理,前面我们已经讲解了Map,WeakMap,Set,WeakSet,Proxy,Reflect这几个知识点。那么接下来思考下到底什么是响应式,就比如我们做一个公司的官网,然后要求必须兼容手机端,ipad端,电脑端,内容屏幕大小变化而变化,这些就需要依赖Ja

Vue3.0 高频出现的几道面试题

1、Vue3.0性能提升主要是通过哪几方面体现的?1.响应式系统提升vue2在初始化的时候,对data中的每个属性使用definepropery调用getter和setter使之变为响应式对象。如果属性值为对象,还会递归调用defineproperty使之变为响应式对象。vue3使用proxy对象重写响应式。proxy的性能本来比defineprope

「快速学习系列」我熬夜整理了Vue3.x响应性API

前言Vue3.x正式版发布已经快半年了,相信大家也多多少少也用Vue3.x开发过项目。那么,我们今天就整理下Vue3.x中的响应性API。响应性APIreactive作用:创建一个响应式数据。本质:传入数据(复杂类型:数组和json对象)包装成一个Proxy对象。如果传入其他对象,默认情况下修改对象,界面不会自动更新,如果想更新,可以通过重新赋值(创建

「快速学习系列」我熬夜整理了Vue3.x响应性API

前言Vue3.x正式版发布已经快半年了,相信大家也多多少少也用Vue3.x开发过项目。那么,我们今天就整理下Vue3.x中的响应性API。响应性APIreactive作用:创建一个响应式数据。本质:传入数据(复杂类型:数组和json对象)包装成一个Proxy对象。如果传入其他对象,默认情况下修改对象,界面不会自动更新,如果想更新,可以通过重新赋值(创建