React中useMemo异步取数后数组无法正常访问问题求助
异步请求导致数组无法正常访问的问题解决
我通过fetch获取数据存入数组后,能在控制台看到完整数组,但无法访问单个元素或进行map遍历。相关代码及运行日志如下:
原代码
useMemo(() => { // setTabIsLoading(true); console.log(tabIsLoading); const contentArray: Array<anime> = []; fetchingArray.map((animeId: string) => { const animeListHandler = async () => { try { const response = await fetch( `https://api.jikan.moe/v4/anime/${animeId}` ); if (response.ok) { const data = await response.json(); const transformedData = { id: data.data.mal_id, name: data.data.title, image: data.data.images.jpg.large_image_url, description: data.data.synopsis, score: data.data.score, }; contentArray.push(transformedData); } } catch (err) { console.error(err); } }; animeListHandler(); }); if (contentArray) { console.log(contentArray); console.log(contentArray[1]); const content = []; contentArray.map((anime) => { console.log(`anime: ${anime}`); content.push(<AnimePagesBox anime={anime} key={anime.id} />); return; }); console.log(content); setActivePageContent(content); setTabIsLoading(false); } }, [activePage, tabIsLoading]);
运行日志
true Account.tsx:70 [] Account.tsx:71 undefined Account.tsx:78 [] Account.tsx:41 false Account.tsx:70 [] Account.tsx:71 undefined Account.tsx:78 []
尝试过的方法
- 曾尝试将数组存入useState状态,偶尔生效,但返回页面后无输出
- 添加数组长度>0的守卫条件后,遍历仍无法执行
问题根源
核心问题是异步操作未等待:你在map里调用异步函数animeListHandler但没有等待它们完成,导致后续的console.log、map遍历和状态更新代码,在所有fetch请求返回数据前就已经执行了——此时contentArray还是空数组。控制台后续能看到完整数组,是因为异步请求完成后数据被push进去,但这时候页面渲染逻辑已经执行完了。
修复方案
1. 改用Promise.all等待所有请求完成
2. 将异步逻辑移至useEffect(useMemo用于缓存计算结果,不适合处理异步副作用)
3. 正确管理loading状态,避免循环触发
修复后的代码:
useEffect(() => { const fetchAnimeData = async () => { setTabIsLoading(true); try { // 用Promise.all等待所有异步请求完成,直接获取完整数据数组 const contentArray = await Promise.all( fetchingArray.map(async (animeId: string) => { const response = await fetch(`https://api.jikan.moe/v4/anime/${animeId}`); if (response.ok) { const data = await response.json(); return { id: data.data.mal_id, name: data.data.title, image: data.data.images.jpg.large_image_url, description: data.data.synopsis, score: data.data.score, }; } // 请求失败时返回null,后续过滤掉无效数据 return null; }) ); // 过滤掉请求失败的空值 const validAnimes = contentArray.filter(anime => anime !== null); // 生成组件数组 const content = validAnimes.map((anime) => ( <AnimePagesBox anime={anime} key={anime.id} /> )); setActivePageContent(content); } catch (err) { console.error(err); } finally { // 无论请求成功失败,都更新loading状态 setTabIsLoading(false); } }; fetchAnimeData(); }, [activePage]); // 依赖项仅保留activePage,避免因tabIsLoading更新触发循环
关键说明
Promise.all会等待所有fetch请求完成后,一次性返回所有结果组成的数组,确保后续代码操作的是完整数据useEffect是React处理异步副作用(网络请求、DOM操作等)的正确钩子,useMemo的设计目的是缓存同步计算的结果try/catch/finally确保loading状态始终能被重置,避免页面一直处于加载状态- 过滤无效数据(请求失败返回的null),防止渲染组件时出现错误
- 依赖项移除
tabIsLoading,避免每次调用setTabIsLoading都触发effect,造成无限循环
内容的提问来源于stack exchange,提问作者Nikita
相关产品推荐
相关产品推荐

