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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 02:26:18