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

FlatList父组件等待子组件API Promise完成问题求助(含报错)

问题分析与解决方案

错误原因

  1. 无限循环触发请求爆炸:你的useEffect依赖数组中包含userFollower和flwCounter,这两个状态在请求完成后会被更新,导致useEffect反复执行,不断发起新请求,最终造成pending callbacks数量超标(501个)。
  2. 清理函数误用:useEffect的return函数是用来清理副作用(比如取消请求、移除监听)的,你却在里面发起请求,这会在组件卸载或依赖变化时再次触发请求,进一步加剧请求数量问题。
  3. 无请求取消机制:组件卸载后,未完成的请求仍在后台运行,完成后还会调用setState/dispatch,既可能引发内存泄漏,也会增加pending callbacks的数量。

修复步骤

第一步:修正子组件的useEffect逻辑

import { useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';

const UserItem = ({ item, onRequestComplete }) => {
  const dispatch = useDispatch();
  const [userFollower, setUserFollower] = useState(null);
  const [flwCounter, setFlwCounter] = useState(null);

  useEffect(() => {
    // 创建AbortController用于取消请求
    const abortController = new AbortController();
    const signal = abortController.signal;

    const fetchUserData = async () => {
      try {
        // 并行发起两个请求,传入signal支持取消
        const [followerData, followingData] = await Promise.all([
          userFollowers(item.link, { signal }),
          userFollowing(item.item.followers_url, { signal })
        ]);

        // 更新状态和redux
        setUserFollower(followerData);
        dispatch({ type: 'GET_FOLLOWING', payload: followerData });
        
        setFlwCounter(followingData);
        dispatch({ type: 'GET_FOLLOWERS', payload: followingData });

        // 通知父组件当前子组件请求完成
        onRequestComplete?.();
      } catch (e) {
        // 忽略请求取消的错误
        if (e.name !== 'AbortError') {
          console.error('用户数据请求失败:', e);
        }
      }
    };

    // 立即执行请求
    fetchUserData();

    // 组件卸载/依赖变化时取消请求
    return () => abortController.abort();
  }, [item, dispatch, onRequestComplete]); // 仅保留必要依赖,避免循环

  // 渲染子组件UI
  return (
    <div>
      {/* 展示userFollower和flwCounter内容 */}
    </div>
  );
};

export default UserItem;

第二步:父组件追踪所有子组件请求完成状态

import { useState, useEffect } from 'react';
import { FlatList } from 'react-native';
import UserItem from './UserItem';

const ParentComponent = ({ data }) => {
  const [completedCount, setCompletedCount] = useState(0);
  const [allRequestsDone, setAllRequestsDone] = useState(false);

  // 监听完成数量,判断是否所有请求都已完成
  useEffect(() => {
    if (completedCount === data.length && data.length > 0) {
      setAllRequestsDone(true);
      // 这里写所有请求完成后的业务逻辑
      console.log('所有子组件API请求已完成');
    }
  }, [completedCount, data.length]);

  const handleRequestFinish = () => {
    setCompletedCount(prev => prev + 1);
  };

  const renderItems = (item) => {
    return <UserItem item={item} onRequestComplete={handleRequestFinish} />;
  };

  return (
    <>
      <FlatList
        data={data}
        renderItem={renderItems}
        keyExtractor={(item) => item.id} // 替换为你的item唯一标识字段
      />
      {/* 所有请求完成后展示提示 */}
      {allRequestsDone && <p>全部数据加载完成</p>}
    </>
  );
};

export default ParentComponent;

可选:父组件直接获取所有请求结果

如果需要拿到所有子组件的请求数据,可以通过ref存储所有Promise:

父组件修改部分:

import { useState, useEffect, useRef } from 'react';

const ParentComponent = ({ data }) => {
  const requestsRef = useRef([]);
  const [allUserData, setAllUserData] = useState([]);

  useEffect(() => {
    const waitAllRequests = async () => {
      requestsRef.current = [];
      // 等待所有子组件的请求完成
      const results = await Promise.all(requestsRef.current);
      setAllUserData(results.filter(res => res !== null));
      console.log('所有请求结果:', results);
    };

    if (data.length > 0) waitAllRequests();
  }, [data.length]);

  const addRequestPromise = (promise) => {
    requestsRef.current.push(promise);
  };

  const renderItems = (item) => {
    return <UserItem item={item} addRequest={addRequestPromise} />;
  };

  // ...其余代码
};

子组件修改部分(在useEffect中):

const fetchUserData = async () => {
  try {
    const [followerData, followingData] = await Promise.all([
      userFollowers(item.link, { signal }),
      userFollowing(item.item.followers_url, { signal })
    ]);

    // ...更新状态和redux的代码

    // 返回请求结果给父组件
    return { follower: followerData, following: followingData };
  } catch (e) {
    if (e.name !== 'AbortError') {
      console.error('请求失败:', e);
      return null;
    }
  }
};

// 将Promise传给父组件
const requestPromise = fetchUserData();
addRequest(requestPromise);

内容的提问来源于stack exchange,提问作者salmanaacvf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 11:45:32