01.Vue3组合式API·响应式·模板渲染基础Ref,Reavtive

目录

前言

ref()

ref深层响应特性

DOM更新时机(nextTick之后)

reactive()

ref与reactive区别


前言

Vue提供各种API对View视图进行操作,这里介绍ref和reactive响应式,以及他们的区别

ref()

  • 组合式API中,推荐使用ref来声明响应式状态(模板变量)
  • 当你再模板中使用了ref,并且改变了ref的值,Vue会自动检测值的变化并更新相应DOM。
  • 组件在首次渲染时,Vue会跟踪在渲染过程中使用过的每一个ref。
  • ref被修改时,会触发追踪它的组件的一次重新渲染
  • 重点:.value赋值才会重新渲染模板DOM!

ref声明响应式变量案例

// setup是Vue3的一个特殊钩子函数,相当于语法糖,为组合式API提供便利
// 无需手动编写setup,以及相应的ref解包操作
<script setup>
import { ref } from 'vue'
const count = ref(0)
// 经过ref封装的变量会多出.value
// .value是一组get和set方法,用于Vue来检测ref访问和修改
console.log(count) // { value: 0 }
console.log(count.value) // 0

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

<template>
  <button @click="increment">
    {{ count }}
  </button>
</template>
ref深层响应特性
  • ref声明的变量,即使是嵌套的对象值或者数组值改变,依然会检测响应更新到模板DOM。
  • shallowRef()可以避免深层递归转为响应式
import { ref } from 'vue'

const obj = ref({
  nested: { count: 0 },
  arr: ['foo', 'bar']
})

function mutateDeeply() {
  // 以下都会按照期望工作
  obj.value.nested.count++
  obj.value.arr.push('baz')
}

DOM更新时机(nextTick之后)

  • 响应式状态修改时,DOM会自动更新。但DOM更新并非同步。
  • Vue会在“next tick”更新周期中缓冲所有状态的修改,以确保不管修改了多少次响应式状态,组件只会更新一次。
  • 如果您预期等待DOM更新完成后要执行一些操作,可以使用nextTick()全局API。
import { nextTick } from 'vue'
async function increment() {
  count.value++
  await nextTick()
  // 现在 DOM 已经更新了
}

reactive()

  • reactive在作用,以及使用上与ref()几乎一致。
  • reactive返回的是一个原始对象的Proxy代理对象,该代理对象与原始对象并不相等。
  • 只有代理对象是响应式,更改原始对象并不触发模板DOM更新。
  • shallowReactive()可以退出深层响应。
  • 一致性
    • 对同一个原始对象调用reactive(),会返回同一个Proxy代理对象。
    • 对已存在的Proxy代理对象调用reactive(),会返回其本身。
  • 响应式对象内的嵌套对象依然是Proxy代理对象,该代理对象与原始对象并不相等
  • reactive只能作用于对象类型数据(对象,数组,Map,Set),无法作用于基础数据类型。
  • reactive不能轻易替换整个对象,这会导致第一个建立跟踪链接的对象失去响应性。
  • reactive对解构操作并不友好,
  • 更推荐使用ref
// 代码案例1
const raw = {}
const proxy = reactive(raw)
// 代理对象和原始对象不是全等的
console.log(proxy === raw) // false


// 代码案例2
// 响应式对象内的嵌套对象依然是Proxy代理对象
const proxy = reactive({})
const raw = {}
proxy.nested = raw
console.log(proxy.nested === raw) // false



// 代码案例3:解构时会丢失响应性变化
const state = reactive({ count: 0 })
// 当解构时,count 已经与 state.count 断开连接
let { count } = state
// 不会影响原始的 state
count++
// 该函数接收到的是一个普通的数字
// 并且无法追踪 state.count 的变化
// 我们必须传入整个对象以保持响应性
callSomeFunction(state.count)

ref与reactive区别

  • ref
    • ref仅适用基础数据类型(字符串,数字,布尔值等)和对象类型。
    • ref在处理对象类型时,内部会自动调用reactive转换为响应式代理。
    • ref底层基于reactive二次封装。
    • ref必须通过.value访问或修改属性值(在模板DOM中会自动解构)。
    • 底层
      • 对基础数据类型使用getter/setter劫持,对对象类型通过reactive实现代理。
      • 本质是包含value属性的封装对象,可以直接替换(ref.value = newObj)。
  • reactive
    • reactive仅支持对象类型(包括数组,Map,Set等),无法直接处理基础数据类型。
    • reactive可直接访问属性(如state.count)。
    • reactive通过Proxy实现深度响应式(基于ES6 Proxy实现深度响应式代理,递归追踪嵌套对象变化)。
    • 无法整体替换原始对象,否则失去响应性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星夜温蓝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值