使用customRef自定义Hooks
在前几节中我们提到了customRef,并进行了简单的介绍,下面拿一些例子来说明如何使用customRef自定义Hooks
创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数,该函数接收 track 和 trigger 函数作为参数,并且应该返回一个带有 get 和 set 的对象。
下面展示一个最简单的例子myRef
function myRef(value) {
return customRef((track, trigger) => {
return {
get() {
track(); //告诉Vue这个数据时需要追踪变化的
console.log("getvalue", value);
return value;
},
set(newValue) {
console.log("set", newValue);
value = newValue;
trigger(); //告诉Vue触发界面更新
},
};
});
然后我们结合实际情况举一个案例
<template>
<div>
<p>{{ age }}</p>
<button @click="fun">click</button>
</div>
</template>
<script>
import { ref, customRef } from "vue";
function myRef(value) {
return customRef((track, trigger) => {
return {
get() {
track(); //告诉Vue这个数据时需要追踪变化的
console.log("getvalue", value);
return value;
},
set(newValue) {
console.log("set", newValue);
value = newValue;
trigger(); //告诉Vue触发界面更新
},
};
});
}
export default {
setup() {
let age = myRef(18);
function fun() {
age.value++;
console.log(age);
}
return { age, fun };
},
methods: {},
};
</script>
考虑一个通常情况下会出现的场景,我们需要读取另一个文件里的数据,而这个过程是异步的。
首先是数据,它放在 public 文件夹里:data.json
[
{
"id": 1,
"name": "鲁班"
},
{
"id": 2,
"name": "张三"
},
{
"id": 3,
"name": "李四"
},
{
"id": 4,
"name": "玩儿"
}
]
如果我们并未使用 customRef 来执行自定义:
<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>
如果我们使用customRef :
<template>
<div>
<p>{{ age }}</p>
<!-- <button @click="fun">click</button> -->
</div>
</template>
<script>
import { ref, customRef } from "vue";
// function myRef(value) {
// return customRef((track, trigger) => {
// return {
// get() {
// track(); //告诉Vue这个数据时需要追踪变化的
// console.log("getvalue", value);
// return value;
// },
// set(newValue) {
// console.log("set", newValue);
// value = newValue;
// trigger(); //告诉Vue触发界面更新
// },
// };
// });
// }
function myRef(value) {
return customRef((track, trigger) => {
fetch(value)
.then((res) => {
return res.json();
})
.then((data) => {
console.log(data);
value = data;
trigger();
})
.catch((err) => {
console.log(err);
});
return {
get() {
track(); //告诉Vue这个数据时需要追踪变化的
// 注意点:
// 不能在get中发送网络请求
// 渲染界面 -> 调用get方法 -> 发送网络请求
// 保存数据 -> 更新界面 -> 调用get
console.log("getvalue", value);
return value;
},
set(newValue) {
console.log("set", newValue);
value = newValue;
trigger(); //告诉Vue触发界面更新
},
};
});
}
export default {
// setup 只能是一个同步函数,不能是一个异步函数
setup() {
let age = myRef("../public/data.json");
// function fun() {
// age.value++;
// console.log(age);
// }
return { age };
},
methods: {},
};
</script>
在这个方案中,我将 获取数据的方案 封装存储在 自定义ref 中,在初始化的时候,会在获取数据之后执行 trigger 进行视图层的变化
注意点:
- 不能在get中发送网络请求
- 渲染界面 -> 调用get方法 -> 发送网络请求
- 保存数据 -> 更新界面 -> 调用get
|