FlatList父组件等待子组件API Promise完成问题求助(含报错)
问题分析与解决方案
错误原因
- 无限循环触发请求爆炸:你的
useEffect依赖数组中包含userFollower和flwCounter,这两个状态在请求完成后会被更新,导致useEffect反复执行,不断发起新请求,最终造成pending callbacks数量超标(501个)。 - 清理函数误用:
useEffect的return函数是用来清理副作用(比如取消请求、移除监听)的,你却在里面发起请求,这会在组件卸载或依赖变化时再次触发请求,进一步加剧请求数量问题。 - 无请求取消机制:组件卸载后,未完成的请求仍在后台运行,完成后还会调用
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
相关产品推荐
相关产品推荐

