Vue响应式进阶常用API学习

shallowRef

ref 的浅层作用形式。shallowRef是浅层引用,只会跟踪原始对象的引用,不会跟踪原始对象的属性

<template>
  <div>
    <div>{{ data.name }}</div>
    <div>{{ data.address.city }}</div>
  </div>
</template>
​
<script setup>
import { shallowRef } from 'vue'
const data = shallowRef({
  name: '张三',
  age: 18,
  address: {
    city: '北京'
  }
})
// 下面的更新不会触发视图更新
setTimeout(() => {
  data.value.name = '李四'
  data.value.address.city = '上海'
}, 2000)
// 下面更新会触发视图更新
setTimeout(() => {
  data.value = {
    name: '王五',
    age: 20,
    address: {
      city: '广州'
    }
  }
}, 4000)
</script>
triggerRef

强制触发依赖于一个浅层 ref 的副作用,这通常在对浅引用的内部值进行深度变更后使用。

<template>
  <div>{{ shallow.greet }}</div>
</template>
​
<script setup>
import { shallowRef, watchEffect} from 'vue'
const shallow = shallowRef({
  greet: 'Hello, world'
})
// 触发该副作用第一次应该会打印 "Hello, world"
watchEffect(() => {
  console.log('=====>', shallow.value.greet)
})
setTimeout(() => {
  // 这次变更数据变了,但视图不会更新
  shallow.value.greet = 'Hello, universe'
  // 打印 "Hello, universe"
  console.log('---->>>', shallow.value.greet)
}, 2000);
</script>

强制更新视图

import { shallowRef, watchEffect, triggerRef} from 'vue'
const shallow = shallowRef({
  greet: 'Hello, world'
})
// 触发该副作用第一次应该会打印 "Hello, world"
watchEffect(() => {
  console.log('=====>', shallow.value.greet)
})
setTimeout(() => {
  shallow.value.greet = 'Hello, universe'
  // 更新视图
  triggerRef(shallow)
}, 2000);
customRef

创建一个自定义的 ref,显式声明对其依赖追踪和更新触发的控制方式。

customRef() 预期接收一个工厂函数作为参数,这个工厂函数接受 tracktrigger 两个函数作为参数,并返回一个带有 getset 方法的对象。

一般来说,track() 应该在 get() 方法中调用,而 trigger() 应该在 set() 中调用。然而事实上,你对何时调用、是否应该调用他们有完全的控制权。

示例

创建一个防抖 ref,即只在最近一次 set 调用后的一段固定间隔后再调用:

import { customRef } from 'vue'
​
export function useDebouncedRef(value, delay = 200) {
  let timeout
  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return value
      },
      set(newValue) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          value = newValue
          trigger()
        }, delay)
      }
    }
  })
}

在组件中使用:

<script setup>
import { useDebouncedRef } from './debouncedRef'
const text = useDebouncedRef('hello')
</script>
​
<template>
  <input v-model="text" />
</template>
shallowReactive

reactive()的浅层浅层响应式,和reactive()不同,这里没有深层级的转换:一个浅层响应式对象里只有根级别的属性是响应式的。

<template>
  <h2>进阶练习</h2>
  <div>
    <div>姓名:{{ data.name }}</div>
    <div>所在城市: {{ data.address.city }}</div>
    <div>
      <button style="margin-right: 10px" @click="editName">修改姓名</button>
      <button @click="editCity">修改城市</button>
    </div>
  </div>
</template>
​
<script setup>
import { shallowReactive } from 'vue'
const data = shallowReactive({
  name: 'lan',
  address: {
    city: '广州'
  }
})
// 这是响应式,名字修改后视图会更新
const editName = () => {
  data.name = 'Alan'
}
const editCity = () => {
  // 这是非响应式,修改后视图不会更新,因为它不是根级别
  // data.address.city = '中山'
  // 但可以这样更新,把整个根给替换
  data.address = {
    city: '中山'
  }
}
</script>
shallowReadonly

readonly()的浅层作用形式,只有根级别是只读不可更改的,根级别以下的可更改,只是视图不会更新,但值改变了

<template>
  <h2>进阶练习</h2>
  <div>
    <div>姓名:{{ data.name }}</div>
    <div>所在城市: {{ data.address.city }}</div>
    <div>
      <button style="margin-right: 10px" @click="editName">修改姓名</button>
      <button @click="editCity">修改城市</button>
    </div>
  </div>
</template>
​
<script setup>
import { shallowReadonly } from 'vue'
const data = shallowReadonly({
  name: 'lan',
  address: {
    city: '广州'
  }
})
// 这里是只读不可更改,修改后视图不会更新值未变
const editName = () => {
  data.name = 'Alan'
  console.log('data.name', data.name)
}
const editCity = () => {
  // 这不是响应式,修改后视图不会更新,但它值确实变了
  data.address.city = '中山'
  console.log('data.address.city', data.address.city)
}
</script>
​
<style lang="scss" scoped></style>
​
toRaw

根据一个 Vue 创建的代理返回其原始对象。这是一个可以用于临时读取而不引起代理访问/跟踪开销,或是写入而不触发更改的特殊方法。(toRaw是Vue 3 Composition API中的一个函数,它接收一个由reactivereadonly方法创建的响应式代理对象,并返回该代理对象对应的原始对象。)

<template>
  <h2>进阶练习</h2>
  <div>
    <div>姓名:{{ data.name }}</div>
    <div>所在城市: {{ data.address.city }}</div>
    <div>
      <button style="margin-right: 10px" @click="editName">修改姓名</button>
    </div>
  </div>
</template>
​
<script setup>
import { reactive, toRaw } from 'vue'
const data = reactive({
  name: 'lan',
  address: {
    city: '广州'
  }
})
//
const editName = () => {
  // 把响应式对象改成普通对象
  const rawData = toRaw(data)
  rawData.name = 'lanshun' // 修改原始对象的值,页面不会更新
  // 输出原始对象
  console.log('rawData', rawData)
}
</script>
markRaw

markRaw会将一个对象标记为不可转化为响应式代理对象,并且返回对象本身

<template>
  <h2>进阶练习</h2>
  <div>
    <h2>应用</h2>
    <div>姓名: {{ data.name }}</div>
    <div>年龄: {{ data.age }}</div>
    <div @click="handleChange">修改信息</div>
  </div>
  <div>
    <h2>深入</h2>
    <div>姓名: {{ state.name }}</div>
    <div>年龄: {{ state.age }}</div>
    <div>地址:{{ state.address.city }}</div>
    <div @click="handleChange2">修改信息</div>
  </div>
</template>
​
<script setup>
import { reactive, markRaw } from 'vue'
const baseObj = {
  name: 'Alan',
  age: 23,
  job: '码农'
}
const data = markRaw(baseObj)
​
const handleChange = () => {
  data.name = 'Role'
  // 操作data.name,发现值改变了,但视图不会更新;是因为markRaw()创建的是非响应式的对象;
  console.log('=data==', data)
}
const state = reactive({
  name: 'Alan',
  age: 23,
  job: '码农'
})
// 此时state下的address会变成非响应式对象,不会被追踪,不会更新视图,而其他属性依然是响应式的;
state['address'] = markRaw({ city: '广州' })
const handleChange2 = () => {
  state.address.city = '深圳'
  console.log('state', state)
}
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值