React中useState+useEffect实现搜索防抖与页码即时请求的最佳实践
解决方案与最佳实践
你的核心问题是ESLint的exhaustive-deps警告源于请求函数依赖page和search但未被加入依赖数组,直接添加依赖又会因函数引用频繁变更导致重复触发请求。下面是两种务实的处理方式:
方式一:拆分逻辑 + 稳定函数引用 + 过滤无效触发
- 用
useCallback包裹请求函数,确保只有当page或search变化时,函数引用才更新:
const [page, setPage] = useState(1); // 给初始值避免参数为undefined const [search, setSearch] = useState(''); const fetchData = useCallback(() => { axios.get("/api/your-target-url", { params: { search, page } // 修正axios参数传递格式 }); }, [search, page]);
- 处理页码变更的立即请求:
useEffect(() => { fetchData(); }, [page, fetchData]);
- 处理搜索词的防抖请求,用
useRef记录上一次搜索值,避免因fetchData引用更新触发不必要的定时器:
const prevSearchRef = useRef(search); useEffect(() => { // 仅当搜索词真正变化时才执行防抖逻辑 if (prevSearchRef.current !== search) { const timer = setTimeout(() => { fetchData(); }, 3000); prevSearchRef.current = search; return () => clearTimeout(timer); } }, [search, fetchData]);
方式二:合并逻辑到单个useEffect,区分状态变更类型
这种方式更简洁,用useRef跟踪前一次的状态值,在同一个副作用里判断是页码还是搜索词变化,分别处理:
const [page, setPage] = useState(1); const [search, setSearch] = useState(''); const fetchData = useCallback(() => { axios.get("/api/your-target-url", { params: { search, page } }); }, [search, page]); const prevPageRef = useRef(page); const prevSearchRef = useRef(search); useEffect(() => { if (prevPageRef.current !== page) { // 页码变更,立即发起请求 fetchData(); prevPageRef.current = page; } else if (prevSearchRef.current !== search) { // 搜索词变更,启用防抖请求 const timer = setTimeout(() => { fetchData(); }, 3000); prevSearchRef.current = search; return () => clearTimeout(timer); } }, [page, search, fetchData]);
关键注意点
- 给
useState设置合理初始值,避免请求时参数为undefined引发接口报错。 - 用
useCallback稳定请求函数的引用,既满足ESLint的依赖检查要求,又能避免不必要的副作用触发。 - 用
useRef跟踪前一次状态值,过滤掉因函数引用更新导致的无效副作用执行,从根源上防止重复请求。
内容的提问来源于stack exchange,提问作者gts97
相关产品推荐
相关产品推荐

