在 React 中,ahooks
的 useRequest
是一个非常强大的异步请求管理工具,它不仅能够帮助开发者轻松处理网络请求,还提供了高级功能,如轮询、节流、防抖、缓存等。在 Vue 中,我们可以通过 Vue 3 的组合式 API 实现类似的功能,管理异步请求及其状态。
本文将结合 Vue 3 的 reactive
、ref
和 watchEffect
等功能,介绍如何在 Vue 中实现类似 useRequest
的异步请求 Hook,并展示如何实现一些常见的功能,如轮询、防抖、节流和缓存等。
1. Vue 组合式 API 概述
Vue 3 的组合式 API 提供了 reactive
、ref
、computed
和 watchEffect
等功能,使得我们可以以一种更灵活、模块化的方式构建功能。在这个基础上,我们可以封装一个类似 useRequest
的 Hook,帮助我们更好地管理异步请求的状态。
2. useRequest
在 Vue 中的核心实现
在 Vue 中,我们可以通过以下几个步骤来实现 useRequest
:
2.1 基本结构
我们首先封装一个基础的 useRequest
函数,用来管理请求状态的更新。它会接收一个异步函数 service
以及可选的配置项 options
。
import { reactive, ref } from 'vue';
export function useRequest(service, options = {}) {
const state = reactive({
data: null,
error: null,
loading: false,
});
const run = async (...args) => {
state.loading = true;
state.error = null;
try {
const result = await service(...args);
state.data = result;
state.loading = false;
return result;
} catch (err) {
state.error = err;
state.loading = false;
throw err;
}
};
return {
...state,
run,
};
}
2.2 参数说明
service
:这是一个异步函数,用于发起实际的请求。options
:配置项,用于扩展功能,比如节流、防抖、缓存等。
2.3 run
函数
run
函数是 useRequest
的核心,它封装了异步请求的发起过程,并管理请求的 loading
、data
和 error
状态。
3. 实现高级功能
接下来,我们扩展 useRequest
,实现一些常用的高级功能,如轮询、防抖、节流和缓存等。
3.1 轮询
为了实现轮询功能,我们可以在每次请求完成后,根据设定的间隔时间再次发起请求。我们通过 setInterval
来实现这个功能。
import { onUnmounted } from 'vue';
export function useRequest(service, options = {}) {
const { pollingInterval } = options;
const state = reactive({
data: null,
error: null,
loading: false,
});
let timer = null;
const run = async (...args) => {
state.loading = true;
state.error = null;
try {
const result = await service(...args);
state.data = result;
state.loading = false;
if (pollingInterval) {
timer = setTimeout(() => run(...args), pollingInterval);
}
return result;
} catch (err) {
state.error = err;
state.loading = false;
throw err;
}
};
onUnmounted(() => {
if (timer) clearTimeout(timer);
});
return {
...state,
run,
};
}
通过设置 pollingInterval
,我们可以在请求完成后指定的时间间隔内再次触发请求,并通过 onUnmounted
钩子在组件卸载时清理定时器,避免内存泄漏。
3.2 防抖与节流
防抖和节流是前端开发中常见的功能,尤其在处理频繁请求时非常有用。我们可以使用 lodash
或者自己实现的防抖和节流函数来封装 run
。
import { debounce, throttle } from 'lodash';
export function useRequest(service, options = {}) {
const { debounceWait, throttleWait } = options;
const state = reactive({
data: null,
error: null,
loading: false,
});
const run = async (...args) => {
state.loading = true;
state.error = null;
try {
const result = await service(...args);
state.data = result;
state.loading = false;
return result;
} catch (err) {
state.error = err;
state.loading = false;
throw err;
}
};
const debouncedRun = debounceWait ? debounce(run, debounceWait) : null;
const throttledRun = throttleWait ? throttle(run, throttleWait) : null;
return {
...state,
run: debouncedRun || throttledRun || run,
};
}
在这里,debouncedRun
和 throttledRun
分别通过 lodash
的 debounce
和 throttle
实现。如果用户提供了 debounceWait
或 throttleWait
参数,我们就使用对应的封装函数来管理请求的频率。
3.3 请求缓存
缓存可以避免重复发起相同的请求,从而提高性能。我们可以通过一个简单的 Map
来存储缓存的结果。
const cache = new Map();
export function useRequest(service, options = {}) {
const { cacheKey } = options;
const state = reactive({
data: null,
error: null,
loading: false,
});
const run = async (...args) => {
if (cacheKey && cache.has(cacheKey)) {
state.data = cache.get(cacheKey);
return cache.get(cacheKey);
}
state.loading = true;
state.error = null;
try {
const result = await service(...args);
state.data = result;
cacheKey && cache.set(cacheKey, result);
state.loading = false;
return result;
} catch (err) {
state.error = err;
state.loading = false;
throw err;
}
};
return {
...state,
run,
};
}
通过 cacheKey
参数,我们可以将请求结果存储到 Map
中,并在后续相同请求中直接从缓存中获取结果。
4. 在 Vue 项目中的使用示例
现在我们已经实现了一个功能丰富的 useRequest
,接下来展示它在实际 Vue 项目中的使用。
<template>
<div>
<div v-if="loading">Loading...</div>
<div v-if="error">Error: {{ error.message }}</div>
<div v-if="data">User: {{ data.name }}</div>
<button @click="run">Reload</button>
</div>
</template>
<script>
import { useRequest } from './useRequest'; // 引入我们封装的 useRequest
export default {
setup() {
const getUserInfo = () => fetch('/api/user').then(res => res.json());
const { data, error, loading, run } = useRequest(getUserInfo, {
pollingInterval: 5000, // 每5秒轮询一次
});
return {
data,
error,
loading,
run,
};
},
};
</script>
在这个示例中,我们使用 useRequest
来发起一个用户信息请求,并启用了 5 秒的轮询功能。我们还展示了如何手动重新加载数据。
5. 总结
通过 Vue 3 的组合式 API,我们可以轻松地实现类似 ahooks
的 useRequest
,并为其扩展多种高级功能,如轮询、防抖、节流和缓存。这种模式不仅简化了异步请求的管理,还增强了代码的可维护性和扩展性。
随着项目的复杂度增加,合理封装异步请求逻辑,管理状态和副作用,能够大大提升开发效率。如果你习惯了 React 中的 useRequest
,那么在 Vue 中实现类似的 Hook 将为你带来更好的开发体验。
通过本文,我们展示了如何在 Vue 3 中构建一个强大的异步请求管理工具,希望能为你的项目提供参考和帮助。
原文链接:https://juejin.cn/post/7416567316999553033 作者:lucifer311