浅谈 Mixin、Composition API、Reactive API、Ref API 以及 readonly🔥
Hello,又见面了,我是渔戈!
今天我们来讲讲 Mixin、Composition API、Reactive API、Ref API 以及 readonly
1.认识 Mixin
目前我们是使用组件化的方式在开发整个 Vue 的应用程序,但是组件和组件之间有时候会存在相同的代码逻辑,我们希望对相同的代码逻辑进行抽取。
在 Vue2 和 Vue3 中都支持的一种方式就是使用 Mixin 来完成:
Mixin 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能;
一个 Mixin 对象可以包含任何组件选项;
当组件使用 Mixin 对象时,所有 Mixin 对象的选项将被 混合 进入该组件本身的选项中;
1.1 Mixin 的基本使用
1.2 Mixin 的合并规则
如果 Mixin 对象中的选项和组件对象中的选项发生了冲突,那么 Vue 会如何操作呢?
这里分成不同的情况来进行处理;
情况一:如果是 data 函数的返回值对象
返回值对象默认情况下会进行合并;
如果 data 返回值对象的属性发生了冲突,那么会保留组件自身的数据;
情况二:如何生命周期钩子函数
生命周期的钩子函数会被合并到数组中,都会被调用;
情况三:值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。
比如都有 methods 选项,并且都定义了方法,那么它们都会生效;
但是如果对象的 key 相同,那么会取组件对象的键值对;
1.3 全局混入 Mixin
如果组件中的某些选项,是所有的组件都需要拥有的,那么这个时候我们可以使用全局的 mixin:
全局的 Mixin 可以使用 应用 app 的方法 mixin 来完成注册;
一旦注册,那么全局混入的选项将会影响每一个组件;
1.4 extends
另外一个类似于 Mixin 的方式是通过 extends 属性:
允许声明扩展另外一个组件,类似于 Mixins;
在开发中 extends 用的非常少,在 Vue2 中比较推荐大家使用 Mixin,而在 Vue3 中推荐使用 Composition API
2. Options API 的弊端
在 Vue2 中,我们编写组件的方式是 Options API:
Options API 的一大特点就是在对应的属性中编写对应的功能模块;
比如 data 定义数据、methods 中定义方法、computed 中定义计算属性、watch 中监听属性改变,也包括生命周期钩子;
但是这种代码有一个很大的弊端:
当我们实现某一个功能时,这个功能对应的代码逻辑会被拆分到各个属性中;
当我们组件变得更大、更复杂时,逻辑关注点的列表就会增长,那么同一个功能的逻辑就会被拆分的很分散;
尤其对于那些一开始没有编写这些组件的人来说,这个组件的代码是难以阅读和理解的(阅读组件的其他人);
2.1 认识 Composition API
那么既然知道 Composition API 想要帮助我们做什么事情,接下来看一下到底是怎么做呢?
为了开始使用 Composition API,我们需要有一个可以实际使用它(编写代码)的地方;
在 Vue 组件中,这个位置就是 setup 函数;
setup 其实就是组件的另外一个选项:
只不过这个选项强大到我们可以用它来替代之前所编写的大部分其他选项;
比如 methods、computed、watch、data、生命周期等等
接下来我们一起学习这个函数的使用:
函数的参数
函数的返回值
2.2 setup 函数的参数
我们先来研究一个 setup 函数的参数,它主要有两个参数:
第一个参数:props
第二个参数:context
props 非常好理解,它其实就是父组件传递过来的属性会被放到 props 对象中,我们在 setup 中如果需要使用,那么就可以直接通过 props 参数获取:
对于定义 props 的类型,我们还是和之前的规则是一样的,在 props 选项中定义;
并且在 template 中依然是可以正常去使用 props 中的属性,比如 message;
如果我们在 setup 函数中想要使用 props,那么不可以通过 this 去获取(后面我会讲到为什么);
因为 props 有直接作为参数传递到 setup 函数中,所以我们可以直接通过参数来使用即可;
另外一个参数是 context,我们也称之为是一个 SetupContext,它里面包含三个属性:
attrs:所有的非 prop 的 attribute;
slots:父组件传递过来的插槽(这个在以渲染函数返回时会有作用,后面会讲到);
emit:当我们组件内部需要发出事件时会用到 emit(因为我们不能访问 this,所以不可以通过 this.$emit 发出事件);
2.3 setup 函数的返回值
setup 既然是一个函数,那么它也可以有返回值,它的返回值用来做什么呢?
setup 的返回值可以在模板 template 中被使用;
也就是说我们可以通过 setup 的返回值来替代 data 选项;
甚至是我们可以返回一个执行函数来代替在 methods 中定义的方法:
但是,如果我们将 counter 在 increment 或者 decrement 进行操作时,是否可以实现界面的响应式呢?
答案是不可以;
这是因为对于一个定义的变量来说,默认情况下,Vue 并不会跟踪它的变化,来引起界面的响应式操作;
2.4 setup 不可以使用 this
3. Reactive API
如果想为在 setup 中定义的数据提供响应式的特性,那么我们可以使用 reactive 的函数:
那么这是什么原因呢?为什么就可以变成响应式的呢?
这是因为当我们使用 reactive 函数处理我们的数据之后,数据再次被使用时就会进行依赖收集;
当数据发生改变时,所有收集到的依赖都是进行对应的响应式操作(比如更新界面);
事实上,我们编写的 data 选项,也是在内部交给了 reactive 函数将其编程响应式对象的;
4.Ref API
reactive API 对传入的类型是有限制的,它要求我们必须传入的是一个对象或者数组类型:
如果我们传入一个基本数据类型(String、Number、Boolean)会报一个警告;
这个时候 Vue3 给我们提供了另外一个 API:ref API
ref 会返回一个可变的响应式对象,该对象作为一个 响应式的引用 维护着它内部的值,这就是 ref 名称的来源;
它内部的值是在 ref 的 value 属性中被维护的;
这里有两个注意事项:
在模板中引入 ref 的值时,Vue 会自动帮助我们进行解包操作,所以我们并不需要在模板中通过 ref.value 的方式来使用;
但是在 setup 函数内部,它依然是一个 ref 引用, 所以对其进行操作时,我们依然需要使用 ref.value 的方式;
4.1 Ref 自动解包
模板中的解包是浅层的解包,如果我们的代码是下面的方式
如果我们将 ref 放到一个 reactive 的属性当中,那么在模板中使用时,它会自动解包:
5. 认识 readonly
我们通过 reactive 或者 ref 可以获取到一个响应式的对象,但是某些情况下,我们传入给其他地方(组件)的这个响应式对象希望在另外一个地方(组件)被使用,但是不能被修改,这个时候如何防止这种情况的出现呢?
Vue3 为我们提供了 readonly 的方法;
readonly 会返回原生对象的只读代理(也就是它依然是一个 Proxy,这是一个 proxy 的 set 方法被劫持,并且不能对其进行修改);
在开发中常见的 readonly 方法会传入三个类型的参数:
类型一:普通对象;
类型二:reactive 返回的对象;
类型三:ref 的对象;
5.1 readonly 的使用
在 readonly 的使用过程中,有如下规则:
readonly 返回的对象都是不允许修改的;
但是经过 readonly 处理的原来的对象是允许被修改的;
比如 const info = readonly(obj),info 对象是不允许被修改的;
当 obj 被修改时,readonly 返回的 info 对象也会被修改;
但是我们不能去修改 readonly 返回的对象 info;
其实本质上就是 readonly 返回的对象的 setter 方法被劫持了而已;
5.2 readonly 的应用
那么这个 readonly 有什么用呢?
在我们传递给其他组件数据时,往往希望其他组件使用我们传递的内容,但是不允许它们修改时,就可以使用 readonly 了;
本次的分享就到这里,如果本章内容对你有所帮助的话欢迎点赞+收藏。文章有不对的地方欢迎指出,有任何疑问都可以在评论区留言。希望大家都能够有所收获,大家一起探讨、进步!
往期高分好文:
版权声明: 本文为 InfoQ 作者【渔戈】的原创文章。
原文链接:【http://xie.infoq.cn/article/70c4ab2393f5934fefdb2fe81】。文章转载请联系作者。
评论