《Vue3.0抢先学》系列之:更多响应式API示例

今天是10月24日,“1024”,程序员们的节日!祝广大程序员朋友们事业顺利,头发茂密,健康长寿。

进入今天的正题,这几天,我们陆续学习了解了关于Vue3.0的一些新特性,尤其是新的Composition API的用法。这套新的API中最重要、最核心的部分,恐怕就是实现响应式功能的这一块了。而且,这套响应式API不仅可以在Vue3.0环境下使用,也可以独立使用。

响应式API主要由2大类组成:

  • 针对原始的数据,将其包装成可观察数据的API (ref、reactive)
  • 针对可观察数据的变动,执行监听和响应动作的API (effect、computed)

包装API和监听API这2者之间互相协同工作,组成一个完整的响应式系统。下面我们来通过一些简单的例子,观察和了解一下它们是如何进行协同工作的。

示例一:ref + effect

在前面的文章中我们提到过,ref 函数可以将一个数据包装成一个响应式数据对象(Ref类型),该函数的TypeScript类型定义如下:

function ref(raw: T): Ref

effect 函数则可以接受一个监听函数,如果这个监听函数中存在对响应式数据对象的访问,则一旦这些响应式数据对象的值发生变化,该监听函数就会被执行。

来看一个简单的代码示例:


const { ref, effect } = Vue

// 创建观察对象
const greeting = ref("Hello,World!")

// 监听数据变化
effect(() => {
    console.log(greeting.value)
})

// 再让数据改变一下吧
greeting.value = "Are you OK?"

以上这段代码先使用 ref 函数创建了一个名为 greeting 的可观察对象,然后通过 effect 函数创建对 greeting 值变化的监听器,对值进行打印。这段代码的执行结果是打印出:

Hello,World!
Are you OK?

这个还是很好理解的,因为这个 greeting 包含的值一共变化了2次,第一次是初始化时设置的 “Hello,World!”,第二次是后面设置的 "Are you OK?"。

示例二:ref 作用于数组数据

在Vue2.x中,对一个数组中的每个元素进行响应式变化监听,做起来还是稍微有点麻烦和不优雅的。在Vue3.0中,这个问题被很好的解决了。

const { ref, effect } = Vue

// 创建一个对数组的观察对象
const arr = ref([1, 2, 3])

effect(() => {
    console.log(arr.value[0])
})

// 改变整个数组
arr.value = [5, 6, 7]

// 改变数组中的第一个元素
arr.value[0] = 111

上面这段代码示例输出的结果是:

1
5
111

由此可以说明,在这段代码中,无论是对整个数组重新赋值,还是对数组中的某个元素赋值,都可以被精准的监听到。

示例三:ref 的嵌套

由 ref 函数创建的可观察对象可以嵌套使用。

const { ref, effect } = Vue

const a = ref(1)
const b = ref(2)
const c = ref({ x: a, y: b })

effect(() => {
    console.log(c.value.x + c.value.y)
})

// 从c对象上去间接改变a和b值
c.value.x = 5
c.value.y = 10

// 直接改变a和b的值
a.value = 20
b.value = 60

可以看到,可观察对象 c 中包含了对其他2个可观察对象 a 和 b的引用。这段代码的最终执行结果为如下:

3
7
15
30
80

由此可见,无论是通过嵌套引用来改变可观察对象值,或是直接改变可观察对象值,effect 创建的监听器都能正确响应这些变化。

示例四:reactive + effect

之前的文章中也提到过,除了 ref 函数,reactive 是Composition API中的另一个可用于创建可观察对象的函数。最简单的用法如下:

const { reactive, effect } = Vue

const state = reactive({ a: 1, b: 'Hello' })

effect(() => {
    console.log(state.a)
})

state.a = 2

使用 reactive 的好处是一次性可以观察多个属性。不过,自从ES6+流行后,我们在实际的代码编写过程中,是不是经常会用到对象解构操作?比如像这样:

const obj = { a: 1, b: 2 }
const { a, b } = obj

而在对可观察对象进行操作的时候,你一定也会自然而然的想这么干:

const state = reactive({ a: 1, b })
let { a, b } = state

state.a = 123 //可以
a = 123 // 行不通!变成不可观察了

为什么将可观察对象中的属性解构出来后,变成不再可观察了呢?因为通过 reactive 函数创建的可观察对象,内部的属性本身并不是可观察类型的,对他们访问和观察其实都是通过Proxy代理访问来实现的。如果将这些属性解构,这些属性就不再通过原对象的代理来访问了,就无法再进行观察。

不过,Composition API也考虑到了这一点,提供了方法来解决这一个问题:

const { reactive, effect, toRefs } = Vue

const state = reactive({ a: 1, b: 2 })

// 这里的a和b都是Ref类型对象
const { a, b } = toRefs(state)

effect(() => {
    console.log(a.value)
})

a.value = 123

通过引入一个 toRefs 函数,它可以将 reactive 创建的可观察对象中的属性都转换成可观察的 Ref 对象,这样一来,即使解构后,也可以被独立进行观察了。

示例五:computed

用过Vue的朋友,一定对计算属性不陌生,一般用于定义一个虚拟属性,这个虚拟属性的值来源于一个或多个可观察对象的变化而产生。在Composition API中也有对应的功能:

const { computed, ref } = Vue

// 可观察对象
const num = ref(1)

// 计算属性
const text = computed(() => {
    return `Value is ${num.value}`
})

console.log(text.value)

// 改动可观察对象的值
num.value = 2

console.log(text.value)

这个例子中,我们根据数字类型的 num,来生成新的字符串 text,实现了一个比较方便的数据生成转换。

总结

Vue 3.0的Composition API提供了上文示例中所展示的这些简单而有效的函数,实现了响应式功能。其实它们还提供了一些可选项参数,用于实现更为丰富的功能,大家可以自己阅读源码深入研究一下,非常有意思,同时也可以从优秀的源码中学习和提高自己的编程水平。

《Vue3.0抢先学》系列之:更多响应式API示例_第1张图片
关注首发公众号:默碟

最新推荐阅读:
《Vue3.0抢先学》系列文章

你可能感兴趣的:(《Vue3.0抢先学》系列之:更多响应式API示例)