学习Vue时候随手写的东西-1

本文最后更新于:2023年6月25日 晚上

响应式

使用reactive()创建响应式对象或数组

我们可以使用reactive()函数创建一个响应式对象或数组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script setup>
import { reactive } from 'vue'

const state = reactive({ count: 0 })

function increment() {
state.count++
}
</script>

<template>
<button @click="increment">
{{ state.count }}
</button>
</template>

可以看到如果要访问state的属性的话,直接使用.运算符即可。
值得注意的是,reactive()返回的是一个原始对象的 Proxy,它和原始对象是不相等的:

1
2
3
4
5
const raw = {}
const proxy = reactive(raw)

// 代理对象和原始对象不是全等的
console.log(proxy === raw) // false

由于JS会自动转型,所以在JS中,两个等号是会先将两边的值转为布尔型再进行比较,而三个等号就是严格判定,可以说JS中的三个等号等于其他语言中的两个等号。
reactive()API有两条限制:

  1. 仅对对象类型有效(对象、数组和MapSet这样的集合类型),而对stringnumberboolean这样的原始类型无效。
  2. 因为 Vue 的响应式系统是通过属性访问进行追踪的,因此我们必须始终保持对该响应式对象的相同引用。这意味着我们不可以随意地“替换”一个响应式对象,因为这将导致对初始引用的响应性连接丢失,同时这也意味着当我们将响应式对象的属性赋值或解构至本地变量时,或是将该属性传入一个函数时,我们会失去响应性。

使用ref()定义响应式变量

reactive()的种种限制归根结底是因为JavaScript没有可以作用于所有值类型的 “引用” 机制。为此,Vue提供了一个ref()方法来允许我们创建可以使用任何值类型的响应式ref:

1
2
3
import { ref } from 'vue'

const count = ref(0)

ref()将传入参数的值包装为一个带.value属性的ref对象:

1
2
3
4
5
6
7
const count = ref(0)

console.log(count) // { value: 0 }
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

当ref在模板中作为顶层属性被访问时,它们会被自动“解包”,所以不需要使用.value。下面是之前的计数器例子,用ref()代替:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script setup>
import { ref } from 'vue'

const count = ref(0)

function increment() {
count.value++
}
</script>

<template>
<button @click="increment">
{{ count }} <!-- 无需 .value -->
</button>
</template>

跟响应式对象不同,当ref作为响应式数组或像Map这种原生集合类型的元素被访问时,不会进行解包。

1
2
3
4
5
6
7
const books = reactive([ref('Vue 3 Guide')])
// 这里需要 .value
console.log(books[0].value)

const map = reactive(new Map([['count', ref(0)]]))
// 这里需要 .value
console.log(map.get('count').value)

一定要注意解包!看下面!

请注意,仅当ref是模板渲染上下文的顶层属性时才适用自动“解包”。例如,foo是顶层属性,但object.foo不是。

1
2
3
4
5
6
7
const object = { foo: ref(1) }
{{ object.foo + 1 }} // 行不通!
{{ object.foo.value + 1 }} // 但是可以手动解包
{{ object.foo }} // 语法糖

const { foo } = object
{{ foo + 1 }} // 正确的!

不同点

reactive()容易丢失响应式链接,比如:

1
2
3
4
let state = reactive({ count: 0 })
let n = state.count
// 不影响原始的state,n在怎么自增state.count都是0
n++

但是ref()就不是了,把上边的换成ref的话count是会跟着n一起变的。
以及传入函数中,也会丢失reactive()响应性,但是ref()不会:

1
2
3
4
5
6
7
8
9
10
11
12
13
let state = reactive({ count: 0 })
// 该函数接收一个普通数字,并且
// 将无法跟踪 state.count 的变化
callSomeFunction(state.count)

const obj = {
foo: ref(1),
bar: ref(2)
}
// 该函数接收一个 ref
// 需要通过 .value 取值
// 但它会保持响应性
callSomeFunction(obj.foo)

在上面的例子中,如果函数中用到传入的值的话,state.count一直是0,无论它之后是否变化。而obj.foo传进去的是响应式对象,利用.value就能跟踪状态取最新值。


这里有一只爱丽丝

希望本文章能够帮到您~


学习Vue时候随手写的东西-1
https://map1e-g.github.io/2022/11/23/vue-learning-1/
作者
MaP1e-G
发布于
2022年11月23日
许可协议