vue3学习记录-ref
- [1.未包裹ref 或则 rective 的变量不是响应式的](#1.未包裹ref 或则 rective 的变量不是响应式的)
- [2.ref, Ref, isRef](#2.ref, Ref, isRef)
- 3.shallowRef
- 4.triggerRef
- 5.customRef
-
- [5.1 防抖 ref](#5.1 防抖 ref)
- [5.2 节流ref](#5.2 节流ref)
- [5.3 与本地存储同步的响应式变量](#5.3 与本地存储同步的响应式变量)
1.未包裹ref 或则 rective 的变量不是响应式的
javascript
<script setup lang="ts">
//未包裹ref 或则 rective 的变量不是响应式的
let message: string = 'Hello Vite + Vue 3 + TypeScript!'
const changeMsg = () => {
message = 'Hello Vite + Vue 3 '
console.log(message)
}
</script>
<template>
<el-button @click="changeMsg">改变</el-button>
<span>message:{{ message }}</span>
</template>
<style scoped>
</style>
2.ref, Ref, isRef
javascript
<script setup lang="ts">
//isRef
import { ref, Ref, isRef } from 'vue'
const msg: Ref<string> = ref('Hello Vite + Vue 3 + TypeScript!')
const notref: number = 999
const demo = ref<String>('Hello Vite')
const changeMsg2 = () => {
msg.value = 'Hello Vite + Vue 3 '
console.log(msg.value)
console.log('demo', demo)
console.log(isRef(msg))
console.log(isRef(notref))
}
</script>
<template>
<el-button @click="changeMsg2">isRef</el-button>
<span>msg:{{ msg }}</span>
</template>
<style scoped></style>
3.shallowRef
shallowRef 是 Vue 3 中的一个响应式 API,用于创建一个浅层响应式引用。它的主要作用是只让引用的值本身变为响应式,而不会递归地使其内部属性变为响应式。这在处理大型对象或需要优化性能时特别有用。
javascript
<template>
<div>
<p>名字: {{ user.name }}</p>
<p>年龄: {{ user.age }}</p>
<button @click="updateName">更新名字</button>
<button @click="updateAge">更新年龄</button>
</div>
</template>
<script setup lang="ts">
import { shallowRef,Ref } from 'vue'
type Obj = {
name:string,
age:number
}
const user:Ref<Obj> = shallowRef({
name: '张三',
age: 25
})
function updateName() {
user.value.name = '李四' // 这不会触发视图更新
console.log('名字已更新,但视图不会立即反应',user)
}
function updateAge() {
user.value = { ...user.value, age: 26 } // 这会触发视图更新
console.log('年龄已更新,视图会更新',user)
}
</script>
让我们考虑一个场景,我们需要处理一个包含大量数据的用户配置文件。
javascript
<template>
<div>
<h1>用户配置文件</h1>
<p>用户名: {{ userProfile.username }}</p>
<p>邮箱: {{ userProfile.email }}</p>
<button @click="updateEmail">更新邮箱</button>
<button @click="refreshProfile">刷新整个配置文件</button>
<!-- 假设这是一个很大的列表 -->
<h2>用户偏好</h2>
<ul>
<li v-for="(value, key) in userProfile.preferences" :key="key">
{{ key }}: {{ value }}
</li>
</ul>
</div>
</template>
<script setup>
import { shallowRef } from 'vue'
// 模拟一个大型用户配置文件对象
const userProfile = shallowRef({
username: '张三',
email: 'zhangsan@example.com',
preferences: {
theme: 'dark',
fontSize: 'medium',
language: 'zh-CN',
notifications: true,
// ... 假设这里有成百上千的偏好设置
},
friends: [
// ... 假设这里有一个很长的朋友列表
],
posts: [
// ... 假设这里有用户的所有帖子
],
// ... 其他大量数据
})
function updateEmail() {
// 这不会触发整个对象的响应式更新
userProfile.value.email = 'newemail@example.com'
console.log('邮箱已更新,但视图不会立即反应')
}
function refreshProfile() {
// 这会触发整个对象的响应式更新
userProfile.value = {
...userProfile.value,
email: 'refreshed@example.com',
// 在实际应用中,这里可能是从服务器获取的新数据
}
console.log('整个配置文件已刷新,视图会更新')
}
</script>
在这个例子中:
- 性能优化:使用 shallowRef 创建 userProfile,避免了对整个大型对象进行深层响应式转换。这对性能有显著影响,特别是当对象包含大量嵌套数据时。
- 选择性更新:updateEmail 函数演示了如何更新单个属性而不触发整个对象的响应式更新。这在频繁更新小部分数据时非常有用,可以避免不必要的渲染。
- 完整刷新:refreshProfile 函数展示了如何在需要时更新整个对象。这适用于从服务器获取新的完整配置文件数据的情况。
- 大型数据处理:用户偏好、朋友列表和帖子等大型数据集合被包含在对象中,但不会被递归地转换为响应式。这大大减少了内存使用和初始化时间。
- 视图更新控制:只有当整个 userProfile 对象被替换时(如在 refreshProfile 中),视图才会完全更新。这给了开发者更多控制,可以选择何时触发大规模的视图更新。
这种方法的优势:
初始化速度更快:对于大型对象,避免深层响应式转换可以显著减少初始化时间。 内存使用更少:不会为每个嵌套属性创建响应式包装器。
更好的性能:减少了不必要的响应式更新和重新渲染。 更精确的控制:开发者可以决定何时更新整个对象,从而触发视图更新。
在实际应用中,这种方法特别适用于处理大型配置对象、复杂的数据模型或需要频繁更新的大型数据集。它允许您在保持响应式能力的同时,最小化性能开销。
4.triggerRef
主要用于手动触发 shallowRef 或 customRef 的更新。它的作用是强制触发依赖于该 ref 的副作用(如计算属性或监听器)重新运行,并更新相关的视图。
javascript
<template>
<div>
<h2>用户信息</h2>
<p>名字: {{ user.name }}</p>
<p>年龄: {{ user.age }}</p>
<p>计算属性 - 成年: {{ isAdult }}</p>
<button @click="updateAge">更新年龄</button>
<button @click="forceUpdate">强制更新</button>
</div>
</template>
<script setup lang="ts">
import { shallowRef, computed, triggerRef,Ref } from 'vue'
type Obj ={
name: string,
age: number
}
const user:Ref<Obj> = shallowRef({
name: '张三',
age: 17
})
const isAdult = computed(() => {
console.log('计算属性被重新计算')
return user.value.age >= 18
})
function updateAge() {
user.value.age = 18
console.log('年龄已更新,但视图和计算属性不会自动更新')
}
function forceUpdate() {
triggerRef(user)
console.log('强制更新触发,视图和计算属性将更新')
}
</script>
使得原本的shallowRe不能更新视图的写法能强制更新视图了。
5.customRef
customRef 是 Vue 3 中的一个高级响应式 API,它允许你创建一个自定义的响应式引用,完全控制其依赖追踪和更新触发行为。这个 API 提供了极大的灵活性,使你能够实现复杂的响应式逻辑。
5.1 防抖 ref
创建一个防抖 ref,即只在最近一次 set 调用后的一段固定间隔后再调用
javascript
<template>
<div>
<input v-model="searchQuery" placeholder="输入搜索词" />
</div>
</template>
<script setup>
import { customRef } from 'vue'
function useDebouncedRef(value, delay = 500) {
let timeout
return customRef((track, trigger) => {
return {
get() {
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
console.log('触发了set')
value = newValue
trigger()
}, delay)
}
}
})
}
const searchQuery = useDebouncedRef('search')
</script>
5.2 节流ref
javascript
function throttlingCustomRef(value,delay = 200){
let lastCall = 0
return customRef((track,trigger)=>{
return {
get(){
track()
return value
},
set(newValue){
const now = Date.now()
if(now - lastCall >= delay){
value = newValue
lastCall = now
trigger()
}
}
}
})
}
5.3 与本地存储同步的响应式变量
创建一个自动与 localStorage 同步的响应式引用。
javascript
import { customRef } from 'vue'
function useLocalStorageRef(key, defaultValue) {
return customRef((track, trigger) => ({
get() {
track()
const value = localStorage.getItem(key)
return value !== null ? JSON.parse(value) : defaultValue
},
set(newValue) {
localStorage.setItem(key, JSON.stringify(newValue))
trigger()
}
}))
}
// 使用示例
const username = useLocalStorageRef('username', '')
还有很多很多的自定义ref