如何在for of循环中为每个迭代单独实现lodash防抖?
问题分析
你遇到的核心问题是:lodash的debounce函数在连续调用时会重置延迟计时器。在for循环中快速调用同一个debouncedFetchData函数10次,防抖机制会取消前9次调用,只保留最后一次执行,最终导致animeData仅存入1个对象。
解决方案
方案一:为每个ID创建独立防抖函数
要实现每个迭代单独防抖,必须为每个请求ID生成独立的防抖函数,避免共用计时器。可以用useRef缓存每个ID对应的防抖实例:
import { useEffect, useState, useMemo, useCallback, useRef } from 'react'; // ... 其他导入 const AnimeRecommendations = ({id}) => { // ... 其他状态和hooks // 缓存每个id对应的防抖函数 const debouncedFetches = useRef({}); // 动态获取或创建对应id的防抖函数 const getDebouncedFetch = useCallback((id) => { if (!debouncedFetches.current[id]) { debouncedFetches.current[id] = debounce(async () => { const anime = await fetchAnimeData(id); setAnimeData(prevData => [...prevData, anime]); }, 1000); } return debouncedFetches.current[id]; }, []); useEffect(() => { const fetchDataForRecommendations = () => { if (recommendations.length) { // 先清空数据,避免旧数据干扰 setAnimeData([]); recommendations.forEach(item => { const fetchFn = getDebouncedFetch(item.entry.mal_id); fetchFn(); }); } }; fetchDataForRecommendations(); // 组件卸载时清理所有防抖计时器,避免内存泄漏 return () => { Object.values(debouncedFetches.current).forEach(fn => fn.cancel()); }; }, [recommendations, getDebouncedFetch]); // ... 其他渲染逻辑 }
方案二:改用间隔执行(控制请求频率)
如果你的真实需求是避免一次性发送大量请求,而是每隔1秒发起一个请求,无需每个请求单独防抖,可以用递归+setTimeout实现:
useEffect(() => { const fetchDataForRecommendations = async () => { setAnimeData([]); if (!recommendations.length) return; // 递归逐个发起请求,间隔1秒 const fetchNext = async (index) => { if (index >= recommendations.length) return; const item = recommendations[index]; const anime = await fetchAnimeData(item.entry.mal_id); setAnimeData(prev => [...prev, anime]); setTimeout(() => fetchNext(index + 1), 1000); }; fetchNext(0); }; fetchDataForRecommendations(); }, [recommendations]);
额外优化点
原代码中useEffect里先调用fetchDataForRecommendations再执行setAnimeData([]),会导致先添加数据再清空,建议将setAnimeData([])放在请求逻辑之前,避免数据闪烁。
内容的提问来源于stack exchange,提问作者Akio
相关产品推荐
相关产品推荐

