React中API调用后setPage自增不生效问题求助
问题原因与解决方案
核心问题是闭包陷阱:组件挂载时创建的fetchData和handleScroll函数捕获了初始的page(值为1)和loading状态,后续状态更新后,这两个函数内部依然使用旧的state值,导致每次请求都用page=1,且滚动时的loading判断也无法阻止重复请求。
具体修复步骤:
- 用
useCallback包裹fetchData,明确依赖项,确保每次state更新后,函数能获取最新的page、loading等状态值。 - 更新滚动事件的
useEffect依赖数组,加入handleScroll,保证滚动触发的是最新的函数,避免使用旧闭包。 - 处理
props的依赖,将props.apiKeys加入相关依赖数组,避免因props更新导致的状态不一致。
修改后的完整代码:
import React, { useEffect, useState, useCallback } from "react"; import axios from "axios"; import { API_URL } from "../configure/config"; const InfiniteScroll = (props) => { const [data, setData] = useState([]); const [page, setPage] = useState(1); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const hr = props.apiKeys?.data.__qhrkey; const toe = props.apiKeys?.data.__token; // 初始加载数据 useEffect(() => { fetchData(); }, [fetchData]); // 用useCallback包裹,确保获取最新state const fetchData = useCallback(() => { if (loading) return; setLoading(true); setError(null); const url = "/services/getScheduleDetails"; const params = { __hr: hr, __toe: toe, __p: page }; const api = API_URL + url; axios .post(api, params) .then((response) => { setData((prevData) => [...prevData, ...response.data]); setPage((prevPage) => prevPage + 1); setLoading(false); }) .catch((error) => { setError(error); setLoading(false); }); }, [page, loading, hr, toe]); const handleScroll = useCallback(() => { if ( window.innerHeight + document.documentElement.scrollTop !== document.documentElement.offsetHeight || loading ) { return; } fetchData(); }, [loading, fetchData]); // 滚动事件依赖handleScroll,确保事件触发最新逻辑 useEffect(() => { window.addEventListener("scroll", handleScroll); return () => { window.removeEventListener("scroll", handleScroll); }; }, [handleScroll]); return ( <div> {data.map((item) => ( <div key={item.id}>{item.title}</div> ))} {loading && <div>加载中...</div>} {error && <div>错误:{error.message}</div>} </div> ); }; export default InfiniteScroll;
关键修改说明:
useCallback包裹fetchData和handleScroll,让它们在依赖项变化时重新创建,确保能访问最新的state和props。- 初始加载的
useEffect依赖fetchData,保证第一次调用的是最新的fetchData函数。 - 给
props.apiKeys添加可选链操作符?.,避免props未初始化时的报错。
内容的提问来源于stack exchange,提问作者Hacker
相关产品推荐
相关产品推荐

