You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中API调用后setPage自增不生效问题求助

问题原因与解决方案

核心问题是闭包陷阱:组件挂载时创建的fetchData和handleScroll函数捕获了初始的page(值为1)和loading状态,后续状态更新后,这两个函数内部依然使用旧的state值,导致每次请求都用page=1,且滚动时的loading判断也无法阻止重复请求。

具体修复步骤:

  1. 用useCallback包裹fetchData,明确依赖项,确保每次state更新后,函数能获取最新的page、loading等状态值。
  2. 更新滚动事件的useEffect依赖数组,加入handleScroll,保证滚动触发的是最新的函数,避免使用旧闭包。
  3. 处理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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 10:12:49