阅读 178

入门即巅峰,Vue3.0学习总结之响应式API

前言

先赞后看,已成习惯。大家好,我是在编程世界里苟且偷生的大海。

本文旨在通俗易懂的描述“响应式API”的概念、作用和语法,作为自己学习的延续和阶段性成果展示。

一、什么是响应性API

  1. 在描述概念之前,先来回顾一下,什么是响应性。

    响应性是一种允许我们以声明式的方式去适应变化的编程范例。

    适应变化?还是很懵……先来看一个非响应性的例子。

    let val1 = 2 let val2 = 3 let sum = val1 + val2 console.log(sum) // 5 val1 = 3 console.log(sum) // 仍然是 5 复制代码

    我们改变了第一个值,sum的值并没有改变。

    相反,如果改变一个值,sum被重新计算和赋值了,那么这就是响应性的。

    export default{   data(){     return {       val1:2,       val2:3     }   },   computed:{     sum(){       return this.val1 + this.val2     }   },   created(){     console.log(this.sum) // 5     this.val1 = 3     console.log(this.sum) // 6 sum会随着改变   } } 复制代码

  2. Vue中的响应性

    上面例子中用到的computed计算属性,就是Vue对响应性的一种实现。

    除此之外,响应性在Vue中还通常表现为:改变绑定在模板上的数据,视图会自动更新。这就是 Vue引以为傲的“响应性系统”,也是Web前端由“操作DOM”到“数据驱动”巨大变革的基石。

    至于它是如何实现的?这是一个耳熟能详、老生常谈的面试题,“介绍一下Vue的响应式原理”。

  3. 在回答完什么是响应性后,什么是响应式API也就不言自喻了 响应式API是Vue3.0新增的,为 JavaScript 对象创建响应式状态/效果的一系列函数/方法的总称。核心语法包括reactive、ref、coumpetd、watch等

二、核心语法介绍

reactive()

  1. 该 API 返回一个响应式的对象状态。使我们可以显式的定义一个响应式状态。

    import { reactive } from 'vue' // 响应式状态 const state = reactive({   count: 0 }) console.log(state) // Proxy {count: 0} 复制代码

    把响应式的对象绑定到模板上,数据变化时,视图就会自动更新。

    <template>   <div>{{ state }}</div> </template> 复制代码

  2. 该响应式转换是“深度转换”——它会影响传递对象的所有嵌套 property。

    const state = reactive({   obj: {    count1: 0, // 注意,比上面多了一层嵌套   } }) // state.obj.count1 也是响应式的 复制代码

  3. 我们定义在data选项中的数据,其响应性也是由 reactive() 实现的。

    当从组件中的 data() 返回一个对象时,它在内部交由 reactive() 使其成为响应式对象。

  4. 基于Proxy跟踪数据变化,避免了 Vue 早期版本中存在的响应性失效问题。 由于 JavaScript 的限制(Object.defineProperty),Vue 不能检测数组和对象的变化。响应性在以下场景会失效:

    var vm = new Vue({   data: {     a: 1   } }) // `vm.a` 现在是响应式的 vm.b = 2 // `vm.b` 不是响应式的 复制代码

    Vue3.0改用ES6的 Proxy 跟踪数据变化,避免了上述问题。如果打印reactive函数的返回,可以明显看到它是一个Proxy对象。

    const state = reactive({   count: 0 }) console.log(state) // Proxy {count: 0} 复制代码

    至于,为什么Object.defineProperty的方案有缺陷,以及为什么Proxy能避免这个问题并有着更好的性能,之前在《一文读懂Vue3的改进与优化》中有详细描述,在此就不赘述了。

    • 当添加或移除对象属性时

    • 当利用索引直接设置一个数组项时

    • 当修改数组的长度时

ref()

  1. 接受一个内部值并返回一个响应式且可变的 ref 对象。

    import { ref } from 'vue' let count = ref(1) console.log(count); // RefImpl {_shallow: false, dep: undefined, __v_isRef: true, _rawValue: 1, _value: 1} 复制代码

    对,它和reactive()一样,都能创建响应式对象。区别在于ref可以接受基础类型的值,而reactive不可以。

  2. 如果接受的值是一个对象,那么它将被 reactive 函数处理为深层的响应式对象。

    const refObj = ref({   count:'1', }) console.log(refObj.value) // Proxy {count: '1'} 复制代码

    此时ref(obj).value 等效于 reactive(obj)

    const obj = {   count:'1' } console.log(ref(obj).value === reactive(obj)) // true 复制代码

  3. 在setup函数中,需要通过.value属性访问和改变它的值

    export default {   setup() {     let count = ref(1); console.log(count.value); // 1 count.value = 2 console.log(count.value); // 2   }, }; 复制代码

  4. 在模板中访问则不需要,Vue会自动对Ref 进行解包

    当 ref 作为渲染上下文 (从 setup() 中返回的对象) 上的 property 返回并可以在模板中被访问时,它将自动浅层次解包内部值。只有访问嵌套的 ref 时需要在模板中添加 .value

    <template>   <div>     // 不需要.value     <span>{{ count }}</span>     <button @click="count ++">Increment count</button>     // 需要.value     <button @click="nested.count.value ++">Nested Increment count</button>   </div> </template> <script>   import { ref } from 'vue'   export default {     setup() {       const count = ref(0)       return {         count,         nested: {           count         }       }     }   } </script> 复制代码

toRefs()

说白了就是,响应式对象版的 解构赋值。它使我们可以像使用 ES6 解构那样,来获取我们想要的响应式对象的属性,且不失去响应性。

  setup() {     const state = reactive({      foo: 1,      bar: 2    })     // 可以在不失去响应性的情况下解构     const { foo, bar } = toRefs(state)     return {       foo,       bar     }   } 复制代码

像这样辅助类的响应式API还有很多,比如使用 readonly 防止更改响应式对象、使用isRef检查值是否为一个 ref 对象等等,就不一一介绍了。

原因有二,①仅使用reactive和ref就能满足大多数的应用场景,延后学习,并不妨碍我们“入门”和做项目;②这类API加起来有十来个,需要消耗不少的精力和注意力,放在入门阶段去啃,凭空增加入门难度。

凡事有个主次,我们大可以走马观花的过一遍API,大致有个印象,等将来用到了再回来补课。

computed()

同选项式API中的computed

const count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 复制代码

watch()

同选项式API中的watch

import { onMounted, ref, watch } from "vue"; // setup中的watch函数,等效选项式API中的watch export default {   setup(props, context) {     let defaultName = ref("码农胖大海");     onMounted(() => {       console.log("mounted!");       // 更新数据以触发watch       defaultName.value = "mounted后的大海";     });     watch(defaultName, (newValue, oldValue) => {       console.log("The defaultName is: " + defaultName.value); // The defaultName is: mounted后的大海       console.log("The defaultName newValue is: " + newValue); // The defaultName newValue is: mounted后的大海       console.log("The defaultName oldValue is: " + oldValue); // The defaultName oldValue is: 码农胖大海     });     return {       defaultName,     };   }, }; 复制代码

三、总结

响应式API可以看做是复合式API的延续,他们是一体的。只是Vue从功能作用上把他们分为了两大类。

这是《入门即巅峰,Vue3.0学习总结》的第三篇。


作者:码农胖大海
链接:https://juejin.cn/post/7045200621825163301

玩站网免费分享SEO网站优化 技术及文章 伪原创工具 https://www.237it.com/ 


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐