Vue3 customRef自定义ref 实现防抖

防抖就是防止在input 框中每输入一个字符就要向服务器请求一次,只要在用户输入完成过一段时间再读取用户输入的内容就能解决这个问题,减小服务器的压力。

**1.**自定义ref是一个函数,可以接受参数。

比如我们自定义一个myRef:

javascript 复制代码
setup() {
  let text = myRef("初始化");

  // 配置自定义的myRef
  function myRef(value) {}

  return { text };
},

**2.**在这个函数中,我们有一个返回值,这个返回值是customRef 函数。

在使用customRef 函数之前,我们需要先对其进行引入:

import { customRef } from "vue";

javascript 复制代码
setup() {
  let text = myRef("初始化");

  function myRef(value) {
    return customRef()
  }

  return { text };
},

**3.**customRef 函数的参数是一个函数。

该函数中又返回一个对象。

对象中有get函数和set函数。

javascript 复制代码
setup() {
  let text = myRef("初始化");

  function myRef(value) {
    return customRef(() => {
      return {
        get() { },
        set() { }
      }
    })
  }

  return { text };
},

**4.**当我们在模板中读取使用自定义ref 定义的数据时就会调用get 函数,修改数据时就会调用set 函数。原理和Proxy 对象中的get、set 差不多。

我们将get 函数中的返回值作为解析模板后数据的值。

而set 函数中,参数newValue为value修改后的值,我们需要将新的值赋值给传入的value值,才能实现页面的响应式。

javascript 复制代码
setup() {
  let text = myRef("初始化");

  function myRef(value) {
    return customRef(() => {
      return {
        // 读取value 调用get
        get() {
          return value;
        },
        // 修改value 调用set
        set(newValue) {
          value = newValue;
        }
      }
    })
  }

  return { text };
},

**5.**以上代码实现后,其实并没有真正实现响应式。至少说我们改变text数据,页面其他用到text的地方并没有改变。

原因就在于我们改变value值后触发get 函数后并没有去重新解析模板,set 也没有收到解析模板的命令。

因此customRef 函数中又有两个参数,track 函数和trigger 函数。

track函数用于通知vue追踪value的变化;trigger函数用于通知vue重新解析模板。

javascript 复制代码
setup() {
  let text = myRef("初始化");

  function myRef(value) {
    return customRef((track, trigger) => {
      return {
        get() {
          track();  // 通知vue追踪value的变化
          return value;
        },
        set(newValue) {
          value = newValue;
          trigger();  // 通知vue重新解析模板
        }
      }
    })
  }

  return { text };
},

**6.**最后我们加上定时器,就能实现防抖的效果。

javascript 复制代码
setup() {
  let text = myRef("初始化", 1000);

  function myRef(value, delay) {
    let timer;  // 定时器
    return customRef((track, trigger) => {
      return {
        get() {
          track();
          return value;
        },
        set(newValue) {
          // 如果定时器已经开启了,就清除当前定时器,新开一个定时器
          clearTimeout(timer);  
          timer = setTimeout(() => {
            value = newValue;
            trigger();
          }, delay);
        },
      };
    });
  }

  return { text };
},
相关推荐
kyriewen12 小时前
我手写了一个 EventEmitter,面试官追问了 6 个问题——第 4 个我没答上来
前端·javascript·面试
IT_陈寒12 小时前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
山河木马13 小时前
矩阵专题2-怎么创建视图矩阵(uViewMatrix)
javascript·webgl·计算机图形学
小林攻城狮13 小时前
使用 Transport 节流解决 Vercel AI SDK 流式渲染卡死问题
前端·react.js
前端缘梦13 小时前
告别 TS 运行时类型漏洞!Zod 完整入门实战教程(前端 / 全栈必备)
前端·react.js·全栈
the_answer13 小时前
Webpack vs Vite 深度对比分析
前端·webpack
转转技术团队13 小时前
验证码识别实战:前端不写页面,改训模型了?
前端
MomentYY13 小时前
Temperature:AI 的“脑洞旋钮”
前端·llm·ai编程
远航_14 小时前
OpenSpec 完整详细介绍
前端·后端
召钱熏14 小时前
状态枚举正确≠渲染正确:一个语音按钮的状态机边界修复实录
android·前端