Vue3 自定义 ref
—— customRef
的使用
本文介绍了Vue3中customRef
API的使用,解释了其在控制响应式数据更新时的优势,特别是实现延迟更新的功能。通过示例代码,展示了如何创建一个带有延迟更新的ref
,并将其封装为可复用的Hook,简化开发过程。customRef
使得开发者能够灵活控制数据的读取和写入时机,提升响应式数据的使用效率。
一、为什么需要 customRef
?
Vue 提供了 ref
和 reactive
来定义响应式数据,但有时我们不希望视图立即更新,比如需要延迟更新。这种情况下,单纯使用 ref
是无法实现的。
举个例子
假设我们在一个 input
中双向绑定一个响应式数据,当用户输入时,数据会立即更新,视图也随之变化。但如果我们希望延迟更新该数据或控制更新频率,customRef
就可以发挥作用了。
二、customRef
的使用
首先,我们需要从 vue
中引入 customRef
:
import { customRef } from 'vue';
如何使用 customRef
?
customRef
是一个函数,它接受一个回调函数作为参数。回调函数要求返回一个对象,且该对象必须包含 get
和 set
两个方法。
get
:在数据被读取时调用。set
:在数据被修改时调用。
基本结构示例:
const delayedRef = customRef((track, trigger) => {
let value;
return {
get() {
track(); // 跟踪数据的依赖
return value;
},
set(newValue) {
value = newValue;
trigger(); // 触发更新
}
};
});
三、延迟更新的实现
为了展示 customRef
的强大功能,我们可以实现一个延迟更新的例子。假设用户输入内容后,只有在停止输入一段时间后数据才会更新。
示例代码:
<template>
<div>
<input v-model="name" placeholder="输入内容后稍等更新"/>
<p>当前值: {{ name }}</p>
</div>
</template>
<script>
import { customRef } from 'vue';
export default {
setup() {
const useDebouncedRef = (value, delay = 300) => {
let timeout;
return customRef((track, trigger) => {
return {
get() {
track(); // 跟踪依赖
return value;
},
set(newValue) {
clearTimeout(timeout);
timeout = setTimeout(() => {
value = newValue;
trigger(); // 延迟后触发更新
}, delay);
}
};
});
};
const name = useDebouncedRef(''); // 使用自定义的延迟ref
return {
name
};
}
};
</script>
解释:
useDebouncedRef
是一个封装好的 hook,它创建了一个带有延迟更新的ref
。- 在
set
方法中,我们使用setTimeout
实现延迟更新,只有当输入停止一段时间后,数据才会更新到视图中。
四、如何封装 customRef
为一个 Hook?
在开发中,customRef
经常会被封装成 hook 以便复用。让我们将上述延迟更新逻辑封装成一个 Hook。
创建 useDebouncedRef.js
文件
import { customRef } from 'vue';
export function useDebouncedRef(value, delay = 300) {
let timeout;
return customRef((track, trigger) => {
return {
get() {
track(); // 跟踪依赖
return value;
},
set(newValue) {
clearTimeout(timeout);
timeout = setTimeout(() => {
value = newValue;
trigger(); // 延迟后触发更新
}, delay);
}
};
});
}
使用封装好的 Hook
在任何需要的地方引入并使用这个 Hook,简化代码:
<template>
<div>
<input v-model="name" placeholder="输入内容后稍等更新"/>
<p>当前值: {{ name }}</p>
</div>
</template>
<script>
import { useDebouncedRef } from './useDebouncedRef';
export default {
setup() {
const name = useDebouncedRef(''); // 使用自定义的延迟ref
return {
name
};
}
};
</script>
五、总结
通过 customRef
,我们可以灵活地控制数据的读取和写入时机,实现像延迟更新等高级功能。在实际开发中,customRef
可以帮助我们创建更加自定义和高效的响应式数据。封装为 Hook 后,使用也非常方便。