ahooks useRequest 踩坑文档:第一个参数类型导致执行次数异常
一、问题现象
在使用 ahooks 的 useRequest 时,发现一个奇怪的现象:当第一个参数传入函数时,请求只会执行一次(符合预期的缓存或依赖触发逻辑);但如果传入Promise,请求会不受控制地多次执行,甚至陷入循环执行的情况。
二、原因解析
要理解这个问题,需从 useRequest 的设计逻辑和参数预期入手:
1. useRequest 对第一个参数的预期
useRequest 的第一个参数是请求函数(Function),该函数需要返回一个 Promise(用于发起异步请求)。useRequest 会根据依赖项、缓存策略等来控制这个函数的执行时机。
示例(正确用法):
jsx
const { data, run } = useRequest(() => {
return axios.get('/api/data');
}, {
// 配置项
});2. 传入 Promise 时的执行逻辑
如果直接传入一个 Promise 而非函数,useRequest 的执行逻辑会被完全破坏:
useRequest在初始化时会立即执行这个 Promise(因为它不是函数,无法被useRequest按逻辑延迟执行)。- 当 Promise 执行后,若触发了组件重渲染(比如数据更新导致组件重新渲染),
useRequest会再次执行这个 Promise(因为它是一个“值”而非“可复用的函数”),从而导致多次执行,甚至循环执行。
示例(错误用法,会导致多次执行):
jsx
// 错误:直接传入 Promise
const promise = axios.get('/api/data');
const { data, run } = useRequest(promise);三、踩坑场景还原
以下场景会复现该问题:
jsx
import { useRequest } from 'ahooks';
import axios from 'axios';
function MyComponent() {
// 错误:第一个参数是 Promise 而非函数
const { data, loading } = useRequest(axios.get('/api/user'));
if (loading) return <div>加载中...</div>;
return <div>用户数据:{data.name}</div>;
}在这个例子中,axios.get('/api/user') 会在组件初始化时立即执行,当请求完成后组件重渲染,useRequest 又会再次执行这个 Promise,导致请求不断重复执行。
四、解决方案
严格遵循 useRequest 的设计规范,第一个参数传入返回 Promise 的函数:
jsx
import { useRequest } from 'ahooks';
import axios from 'axios';
function MyComponent() {
// 正确:传入返回 Promise 的函数
const { data, loading } = useRequest(() => {
return axios.get('/api/user');
});
if (loading) return <div>加载中...</div>;
return <div>用户数据:{data.name}</div>;
}这样 useRequest 就能根据其内部的依赖管理、缓存策略等逻辑,精准控制请求的执行时机,避免多次无意义执行。
五、总结
useRequest第一个参数必须是返回 Promise 的函数,而非直接的 Promise。- 直接传入 Promise 会导致请求在组件重渲染时反复执行,破坏
useRequest的正常逻辑。 - 遵循正确的参数类型传入方式,才能让
useRequest发挥其缓存、防抖、节流等强大能力,保障请求的稳定性和性能。