React使用useEffect时出现无限重复请求问题的解决方法
问题根因
接口无限重复请求的核心原因是React useEffect 对依赖项做引用相等校验,而非值相等校验:
- 你在
App组件的函数体内直接定义了params对象,组件每一次重渲染都会生成一个全新引用的params对象 - 自定义Hook里的
useEffect把params作为依赖项,每次拿到新引用的params都会触发effect执行,调用接口 - 接口请求完成后调用
setData、setLoading会触发组件重渲染,又会生成新的params对象,再次触发effect,形成死循环
修复方案
可以从调用侧、Hook侧两个维度修复,推荐两侧都做处理,鲁棒性更强:
方案1:调用侧缓存参数对象
对于固定不变的请求参数,用useMemo缓存,避免每次渲染生成新引用:
import { useMemo } from 'react'; import { useRequest } from "./hooks/useRequest"; function App() { // 仅当依赖数组内的值变化时,才会重新生成params对象 const params = useMemo(() => ({ pagination: { page: 1, perPage: 10 }, sort: { field: "updatedAt", order: "DESC" }, }), []); // 如果参数有动态值,把对应的变量加到依赖数组即可 const { data, loading } = useRequest("/posts", params); return ( <Layout> <div className="text-white"></div> </Layout> ); } export default App;
方案2:Hook侧优化依赖逻辑
不要直接把整个对象/数组作为依赖项,拆解为基本类型值做依赖,同时缓存请求函数,避免不必要的触发:
import { useState, useEffect, useCallback } from 'react'; // 保留你原有引入的依赖 // import { stringify } from 'xxx'; // import http from 'xxx'; export const useRequest = (resource, params) => { const [data, setData] = useState(); const [loading, setLoading] = useState(false); // 缓存请求函数,仅当resource变化时才重新生成 const fetcher = useCallback((currentParams) => { setLoading(true); const { page, perPage } = currentParams.pagination; const { field, order } = currentParams.sort; const query = { sort: JSON.stringify([field, order]), range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]), filter: JSON.stringify(currentParams?.filter ? currentParams.filter : ""), }; http.get(`${resource}?${stringify(query)}`).then((res) => { setData(res); setLoading(false); }); }, [resource]); useEffect(() => { // 增加参数合法性校验,避免参数缺失时报错 if (!params?.pagination || !params?.sort) return; fetcher(params); // 依赖项拆解为基本类型,值不变就不会重复触发effect }, [ fetcher, params.pagination?.page, params.pagination?.perPage, params.sort?.field, params.sort?.order, params.filter ]); return { data, loading, }; };
补充:如果参数嵌套层级很深,拆解依赖太繁琐,也可以用
JSON.stringify(params)序列化后的字符串作为依赖项,注意保证对象键顺序固定即可。
内容的提问来源于stack exchange,提问作者leet
相关产品推荐
相关产品推荐

