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

React Context中无法将API响应数据设置到State值求助

问题:React Context中无法将API响应数据设置到状态

在构建基础React Context调用无认证API时,确认能获取正确响应且已做类型安全处理,但fetchedData状态始终保持默认空数组。

相关代码

API响应示例

[
{
"id": "C8144412-E7BE-4CC4-BB0A-294938E38BD6",
    "appName": "some App",
    "p1AlertCount": 1,
    "p2AlertCount": 2,
    "appScore": 20,
    "appStatus": true,
    "message": "up and running"
}, 
...
]

Context API代码

import { createContext, useContext, useEffect, useState } from "react";
import AppStatus from "./types";
import axios from "axios";

const AppContext = createContext<AppStatus[] | null>(null);

const api_endpoint: string = `http://localhost:5289/AppStatus`;

const AppProvider = ({ children }: { children: React.ReactNode }) => {
  const [isLoading, setLoading] = useState<boolean>(true);
  const [fetchedData, setFetchedData] = useState<AppStatus[]>([]);

  const fetchData = async (url: string) => {
    try {
      const response = await axios.get(url);
      const appData: AppStatus[] = (await response.data) as AppStatus[];

      if (response.status != 200 || response.statusText != "OK") {
        throw new Error("failed to fetch");
      }

      setLoading(false);
      setFetchedData(appData);
      console.log(appData);
      console.log(fetchedData);
    } catch (error) {
      throw new Error(`error is ${error}`);
    }
  };

  useEffect(() => {
    fetchData(api_endpoint);
  }, []);

  return (
    <AppContext.Provider value={{ isLoading, fetchedData }}>
      {children}
    </AppContext.Provider>
  );
};

const useGlobalContext = () => {
  return useContext(AppContext);
};

export { AppContext, AppProvider, useGlobalContext };

React响应类型定义

export default interface AppStatus {
  id: string;
  appName: string;
  p1AlertCount: number;
  p2AlertCount: number;
  appScore: number;
  appStatus: boolean;
  message: string;
}

API模型代码

namespace App_Health_Mock_API.Model
{
    public class AppDataModel
    {
        public required string Id { get; set; }
        public required string AppName { get; set; }
        public required int P1AlertCount { get; set; } = 0;
        public required int P2AlertCount { get; set; } = 0;
        public required int AppScore { get;set; }
        public required Boolean AppStatus { get; set; } = true;
        public required string Message { get; set; }
    }
}

解决方案

1. 修复重复await问题

axios.get已经通过await拿到完整响应,response.data直接是返回的数据,不需要再次await。重复await会导致appData变成Promise对象而非实际数组,无法正确设置状态。

修改代码:

// 错误写法
const appData: AppStatus[] = (await response.data) as AppStatus[];

// 正确写法
const appData: AppStatus[] = response.data as AppStatus[];

2. 修正Context类型不匹配问题

原createContext的类型是AppStatus[] | null,但Provider传递的是包含isLoading和fetchedData的对象,类型完全不匹配,会导致useGlobalContext返回值可能为null,后续使用异常。

创建正确的Context类型并更新初始化:

// 新增Context类型定义
interface AppContextType {
  isLoading: boolean;
  fetchedData: AppStatus[];
}

// 用正确类型初始化Context,设置合理默认值
const AppContext = createContext<AppContextType>({
  isLoading: true,
  fetchedData: []
});

3. 理解React setState的异步特性

setFetchedData是异步操作,调用后立即console.log(fetchedData)会拿到更新前的旧值,不能以此判断状态是否设置成功。验证状态更新可通过:

  • 在子组件中使用useGlobalContext获取状态并渲染
  • 添加useEffect监听fetchedData变化:
useEffect(() => {
  console.log("fetchedData updated:", fetchedData);
}, [fetchedData]);

4. 优化错误处理(可选)

直接throw new Error会导致组件崩溃,建议添加错误状态并处理:

const [error, setError] = useState<string | null>(null);

// 在catch块中设置错误状态
catch (error) {
  setError(`Failed to fetch data: ${(error as Error).message}`);
  setLoading(false);
}

// 在Provider中传递error状态
<AppContext.Provider value={{ isLoading, fetchedData, error }}>

修改后的完整Context代码

import { createContext, useContext, useEffect, useState } from "react";
import AppStatus from "./types";
import axios from "axios";

interface AppContextType {
  isLoading: boolean;
  fetchedData: AppStatus[];
  error: string | null;
}

const AppContext = createContext<AppContextType>({
  isLoading: true,
  fetchedData: [],
  error: null
});

const api_endpoint: string = `http://localhost:5289/AppStatus`;

const AppProvider = ({ children }: { children: React.ReactNode }) => {
  const [isLoading, setLoading] = useState<boolean>(true);
  const [fetchedData, setFetchedData] = useState<AppStatus[]>([]);
  const [error, setError] = useState<string | null>(null);

  const fetchData = async (url: string) => {
    try {
      const response = await axios.get(url);
      
      if (response.status !== 200 || response.statusText !== "OK") {
        throw new Error("Failed to fetch data");
      }

      const appData: AppStatus[] = response.data as AppStatus[];
      setFetchedData(appData);
      setError(null);
    } catch (error) {
      setError(`Error: ${(error as Error).message}`);
      setFetchedData([]);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    fetchData(api_endpoint);
  }, []);

  // 验证状态更新
  useEffect(() => {
    console.log("Updated fetchedData:", fetchedData);
  }, [fetchedData]);

  return (
    <AppContext.Provider value={{ isLoading, fetchedData, error }}>
      {children}
    </AppContext.Provider>
  );
};

const useGlobalContext = () => {
  return useContext(AppContext);
};

export { AppContext, AppProvider, useGlobalContext };

验证方法

在任意子组件中使用Context:

import { useGlobalContext } from "./AppContext";

const AppList = () => {
  const { isLoading, fetchedData, error } = useGlobalContext();

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>{error}</div>;

  return (
    <ul>
      {fetchedData.map(app => (
        <li key={app.id}>{app.appName}</li>
      ))}
    </ul>
  );
};

export default AppList;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 15:57:11