vue3中customRef自定义ref(系列十)
Vue3 系列 自定义 ref
2023-09-11 14:20:08 时间
customRef
返回一个ref对象,可以显式地控制依赖追踪和触发响应
示例
<template> <div> <p>{{obj}}</p> <button @click="inc">button</button> </div> </template> <script> import { customRef } from 'vue'; // customRef用于 自定义ref // 自定义 ref 需要提供参数传值 function myRef(value) { // 自定义 ref 需要提供 customerRef 返回值 // customer 需要提供一个函数作为参数 // 该函数默认带参数 track 和 trigger ,都是方法。 return customRef((track, trigger) => { return { // customer 需要提供一个对象 作为返回值 // 该对象需要包含 get 和 set 方法。 get() { // track 方法放在 get 中,用于提示这个数据是需要追踪变化的 track(); console.log('get', value); return value; }, // set 传入一个值作为新值,通常用于取代 value set(newValue) { console.log('set', newValue); value = newValue; // 记得触发事件 trigger,告诉vue触发页面更新 trigger(); } } }) } export default { name: 'App', setup() {
// let obj = ref(18); // reactive({value: 18})
// 应用上面的自定义 ref ,使用方案和之前的 ref 是类似的。 const obj = myRef(123); function inc() { obj.value += 1; } return { obj, inc }; } } </script>
这并不是一个多么复杂的方法,如果要使用,记得是在自定义的 ref
中返回一个 customRef
,而 customRef
也要返回一个对象,相当于二重嵌套的返回。
假如我们去掉了 track
和 trigger
,那么将失去视图层追踪变化的能力(可以显示控制)。如果需要进行视图层追踪,请注意在 set
中 value
发生变化后即刻执行 trigger
。
#实例2
考虑一个通常情况下会出现的场景,我们需要发送请求,获取数据,而这个过程是异步的。
首先是数据,它放在 public 文件夹里。
// data.json [ { "name": "GuanYu", "id": 1 }, { "name": "ZhangFei", "id": 2 }, { "name": "MaChao", "id": 3 }, { "name": "ZhaoYun", "id": 4 }, { "name": "HuangZhong", "id": 5 } ]
如果我们并未使用 customRef
来执行自定义。fetch请求详情:阮一峰
<template> <ul> <li v-for="item in obj" :key="item.id"> {{item.id}} - {{item.name}} </li> </ul> </template> <script> import { ref } from 'vue'; export default { name: 'App', setup() { // 创建一个空数组 ref const obj = ref([]); // 使用 fetch 异步获取文件内容 fetch('../public/data.json') .then((res) => { return res.json(); }).then((data) => { console.log(data); obj.value = data; }).catch((err) => { console.log(err); }) return { obj, }; } } </script>
此时在setup函数中(setup函数: 只能是一个同步的函数, 不能是一个异步的函数,如async setup),有多个异步回调函数,不美观,是否可用同步效果呢,可以采用自定义ref实现
这是一个办法,但还有更加具有可复用性的方案。
<template> <ul> <li v-for="item in obj" :key="item.id"> {{item.id}} - {{item.name}} </li> <button @click="getNewObj">newObj</button> </ul> </template> <script> import { customRef } from 'vue'; function fetchRef(value) { return customRef((track, trigger) => { // 用于存储获得的数据 let ans; function getAns() { fetch(value) .then((res) => { return res.json(); }).then((data) => { console.log(data); // 将获得的数据存储起来 ans = data; // 提示触发视图层变化 trigger(); }).catch((err) => { console.log(err); }); } getAns(); return { get() { track(); //告诉vue这个数据需要追踪变化 return ans; }, set(newValue) { value = newValue; // 修改 value 的同时再次进行数据的抓取 getAns(); } } }) } export default { name: 'App', setup() { const obj = fetchRef('../public/data.json'); // 修改数据源 function getNewObj() { obj.value = '../public/data1.json'; } return { obj, getNewObj }; } } </script>
// 注意点:
// 不能在get方法中发送网络请求,会循环发送请求
// 渲染界面 -> 调用get -> 发送网络请求
// 保存数据 -> 更新界面 -> 调用get
在这个方案中,我将 获取数据的方案 封装存储在 自定义ref
中,在初始化的时候,调用get函数,发送请求,会在获取数据之后,在更新页面之前,执行 trigger
进行视图层的变化。
而在设置新值的时候,再次触发获取数据的方案,从而实现复杂的双向数据绑定。在setup函数就实现一个同步代码方式,美观
点击 button
,可以改变数据,并实现视图层的变化。
// data1.json [ { "name": "LiuBei", "id": 6 }, { "name": "CaoCao", "id": 7 }, { "name": "SunQuan", "id": 8 } ]
相关文章
- 43 JS+Vue3制作动画和钩子函数
- 【Vue | vue3】Vue2和Vue3中Element-Ui 的安装与使用
- vite&vue3中使用批量导入 import.meta.glob import.meta.globEager
- vue3 computed计算属性 实现购物车
- Vue3+elementplus搭建通用管理系统实例十二:使用通用表格、表单实现对应功能
- vue3计算属性和侦听与script setup区别使用
- vue3响应式reactive的实现原理;proxy深层代理;vue3响应式api
- 浅析vue3在源码、性能和语法上对比vue2做了哪些优化
- 浅析Vue3使用reactive/toRefs+v-model导致响应式失效el-form表单无法输入的问题
- vue3中toRef和toRefs的情况(系列九)
- vue3中ref注意点(系列五)
- vue3组合API注意点(系列三)
- Vue3:自定义指令以及简单的后台管理权限封装
- 11.0 vue3 shallowRef&shallowReactive
- vue2中Options API 和 vue3中Composition API 的对比