深入理解 Vue 3 Composition API:从 customRef 到其他响应式工具

28 阅读3分钟

Vue 3 引入了 Composition API,为我们提供了更加灵活和强大的方式来组织组件逻辑。在本文中,我们将通过一个具体的 customRef 示例,并扩展介绍其他相关响应式 API,帮助你全面掌握 Vue 3 的响应式系统。

一、自定义响应式引用:customRef

我们先来看一个使用 customRef 实现防抖搜索的示例:

vue

复制下载

<template>
  <div>
    <input type="text" v-model="keyWord"/>
    <h2>{{ keyWord }}</h2>
  </div>  
</template>

<script>
import { customRef } from 'vue';

export default {
  name: 'App',
  setup() {
    // 自定义的防抖 ref 实现
    function myRef(value, delay) {
      let timer;
      return customRef((track, trigger) => {
        return {
          get() {
            console.log(`有人从myRef这个容器中读取数据了,我把${value}给他了`);
            track(); // 通知Vue追踪value的变化
            return value;
          },
          set(newValue) {
            console.log(`有人把myRef这个容器中的数据改为了:${newValue}`);
            clearTimeout(timer);
            value = newValue;
            timer = setTimeout(() => {
              trigger(); // 通知Vue去重新解析模板
            }, delay);
          }
        };
      });
    }

    // 使用自定义ref,设置500ms防抖
    let keyWord = myRef('hello', 500);
    
    return {  
      keyWord
    };
  }
};
</script>

customRef 的核心机制:

  1. track() :在 get 方法中调用,用于依赖收集,告诉 Vue "这个值被读取了,需要跟踪它的变化"
  2. trigger() :在 set 方法中调用,用于触发更新,告诉 Vue "这个值变化了,需要重新渲染"
  3. 自定义控制:通过 customRef,我们可以完全控制何时触发更新,这在实现防抖、节流等场景中非常有用

二、其他重要的 Composition API

1. shallowReactive 与 shallowRef

  • shallowReactive:只处理对象最外层属性的响应式(浅响应式)
  • shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理

使用场景

  • 当对象结构很深,但只有外层属性变化时 → 使用 shallowReactive
  • 当对象数据不会内部修改,而是用新对象替换时 → 使用 shallowRef

2. readonly 与 shallowReadonly

  • readonly:让响应式数据变为深只读
  • shallowReadonly:让响应式数据变为浅只读

应用场景:接收来自外部的数据,确保不会被意外修改。

3. toRaw 与 markRaw

  • toRaw:将 reactive 创建的响应式对象转为普通对象

    • 对普通对象的操作不会触发页面更新
  • markRaw:标记对象,使其永远不会成为响应式对象

    • 适用于第三方类库、大数据列表等场景,提高性能

4. provide 和 inject

实现祖孙组件通信的利器:

javascript

复制下载

// 父组件
setup() {
  provide('userInfo', { name: '张三', age: 25 });
}

// 子组件
setup() {
  const userInfo = inject('userInfo');
  return { userInfo };
}

5. 响应式数据判断工具

  • isRef:检查是否为 ref 对象
  • isReactive:检查是否为 reactive 创建的响应式代理
  • isReadonly:检查是否为 readonly 创建的只读代理
  • isProxy:检查是否为 reactive 或 readonly 创建的代理

三、Composition API 的优势

  1. 更好的代码组织:将相关功能逻辑组织在一起,提高代码可读性和可维护性
  2. 逻辑复用:可以轻松提取和复用响应式逻辑
  3. TypeScript 支持:提供更好的类型推断
  4. 灵活性:可以根据功能而非选项(data、methods等)来组织代码

四、实战建议

  1. 性能优化:对于大型对象或列表,合理使用 shallowReactive 和 shallowRef
  2. 数据保护:使用 readonly 保护不应被修改的数据
  3. 防抖节流:利用 customRef 优雅地实现输入防抖等效果
  4. 组件通信:对于深层嵌套组件,使用 provide/inject 替代多层 props 传递