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

如何使用useContext Hook更新数组?React上下文数据更新问题排查

修复React Context中多组件共享数组更新的问题

让我帮你梳理下代码里的问题,一步步解决这个Context数组更新的问题:

你的代码里的核心错误

  • State初始化逻辑错误:你把包含数组和函数的heroInformation对象作为useState的初始值,但实际上,heroesContext应该是单独的数组state,更新函数feedHeroes应该定义在Provider组件内部,而不是初始state的一部分。这样会导致你的state结构混乱,组件拿到的context不是你期望的结构。
  • setState调用错误:setHeroesContext(...arrayFromAPI)这种写法会把数组的每一项展开作为state的新值,而不是把整个数组作为state。比如如果API返回[hero1, hero2],你这样写会把state设置成hero1,而不是完整的数组。正确的做法是直接传递整个数组。
  • 异步操作的时机问题:在你的useEffect里,第二个.then()里的console.log会在API请求刚发起就执行,而不是在feedHeroes执行完成之后。因为你没有把它包装成回调函数,此时context的heroesContext还没更新,所以看不到正确的值。
  • Context Provider的value传递错误:你当前传递的value={heroesContext}是你的初始state对象,但实际上你应该传递包含最新数组和更新函数的对象,这样组件才能同时拿到数组和更新它的方法。

修正后的代码

Context.js

import React, { useState, useCallback } from "react";

// 给Context设置默认值,避免组件未被Provider包裹时报错
const HeroContext = React.createContext({
  heroesContext: [],
  feedHeroes: () => {}
});

const HeroProvider = props => {
  // 直接将空数组作为heroesContext的初始state
  const [heroesContext, setHeroesContext] = useState([]);

  // 用useCallback包裹更新函数,避免每次渲染都创建新函数,优化组件性能
  const feedHeroes = useCallback((arrayFromAPI) => {
    // 直接将API返回的数组设置为新state
    setHeroesContext(arrayFromAPI);
    console.log("更新后的英雄数组:", arrayFromAPI);
  }, []);

  // 组装要传递给子组件的context内容
  const contextValue = {
    heroesContext,
    feedHeroes
  };

  return (
    <HeroContext.Provider value={contextValue}>
      {props.children}
    </HeroContext.Provider>
  );
};

export { HeroContext, HeroProvider };

Component.js

import React, { useContext, useEffect } from "react";
import { HeroContext } from "../../context/HeroContext";
import defaultSearch from "../../services/api";

const HeroesList = () => {
  // 解构拿到context里的数组和更新函数
  const { heroesContext, feedHeroes } = useContext(HeroContext);

  console.log("当前Context内容:", { heroesContext, feedHeroes });

  useEffect(() => {
    const fetchHeroes = async () => {
      try {
        const response = await defaultSearch.get();
        // 调用更新函数传递API返回的数组
        feedHeroes(response.data.data.results);
        // 这里可以直接打印API返回的数据,因为state更新是异步的,无法立即拿到heroesContext的最新值
        console.log("API返回的英雄数据:", response.data.data.results);
      } catch (error) {
        console.error("获取英雄数据失败:", error);
      }
    };

    fetchHeroes();
  }, [feedHeroes]); // 将feedHeroes作为依赖,因为用了useCallback,它不会频繁变化

  // 监听heroesContext的变化,查看更新后的值
  useEffect(() => {
    console.log("更新后的heroesContext:", heroesContext);
  }, [heroesContext]);

  return (
    <div>
      {/* 渲染英雄列表 */}
      {heroesContext.map(hero => (
        <div key={hero.id}>{hero.name}</div>
      ))}
    </div>
  );
};

export default HeroesList;

额外说明

  • 给Context设置默认值是个好习惯,这样即使组件意外脱离Provider的包裹,也不会因为访问context.feedHeroes而抛出错误。
  • 使用useCallback包裹更新函数,可以避免Provider每次渲染时都生成新的函数,从而防止使用该Context的子组件不必要地重复渲染。
  • React的state更新是异步的,所以在调用feedHeroes后不能立即通过heroesContext拿到最新值,需要通过额外的useEffect监听heroesContext的变化来查看更新后的数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:22:59