Vue - 认识声明响应式状态

声明响应式状态

有两种 ref()reactive()

ref()

ref() 是将普通的 js 数值包装进一个特殊对象中, 对数值的操作需要通过 .value 来进行, 可以用来包装任何类型的值,包括深层嵌套的对象、数组或者 JavaScript 内置的数据结构

内部如何实现响应式操作的?
通过 get, set 操作实现, vue 追踪了每个调用了 get 操作的组件, 然后在 set 被操作时, 触发这些 “追踪对象” 的修改

<script setup>
import { ref } from 'vue'

const count = ref(0)

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

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

reactive()

reactive() 是将对象包装成一个代理对象, 使用上不需要 .value, 直接正常使用, 一般用来包装复杂类型

内部实现方式
通过 Javascripte 代理, 代理了包装对象的所有数据的访问与修改, Vue 通过拦截这些操作进行依赖追踪和触发更新

reactive() 存在局限性, 推荐使用 ref()

  • 只能包装对象类型 (对象、数组和如 MapSet 这样的集合类型)。它不能持有如 stringnumberboolean 这样的原始类型
  • 只能通过代理对象进行操作, 不然就会失去响应性, 不支持替换与解构
<script setup>
import { reactive } from 'vue'

const state = ref({
		count: 0
})

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

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

嵌套与解包注意事项

  • ref() 嵌套进 reactive() 可以自动 解构
    const msg = ref('Hello World!')
    const count = ref(0)
    const state = reactive({
      count,
      msg
    })
    
    function increment() {
      state.count++
      state.msg += "ttt"
    }
    
  • 作为数组或原生集合类型时, 无法自动解构, 需要用 .value
    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)