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

React中如何使用useEffect内API请求获取的notebooks变量?

如何在React组件中使用从API获取的notebooks列表

核心问题分析

  • 你直接给普通变量notebooks赋值,这不是React状态变量,组件不会因为变量变化触发重新渲染,因此JSX中无法获取更新后的数据。
  • getAllNotebooks是异步函数,原代码未添加await,拿到的是Promise对象而非实际返回数据,后续的JSON序列化/反序列化操作完全无效。

解决方案步骤

1. 单组件状态管理方案(基础版)

如果仅在单个组件中处理数据,先通过useState定义状态变量存储notebooks数据:

import { useState, useEffect } from 'react';

function NotebookList() {
  // 定义状态,初始值设为空数组
  const [notebooks, setNotebooks] = useState<[Notebook, Withdraw[]][]>([]);
  // 加载状态,用于显示加载提示
  const [isLoading, setIsLoading] = useState(true);
  // 错误状态
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    // 将useEffect回调封装为async函数
    const fetchNotebooks = async () => {
      try {
        setIsLoading(true);
        const idToken = await getIdToken();
        // 等待异步函数返回结果
        const fetchedNotebooks = await getAllNotebooks(idToken);
        // 更新状态,触发组件重新渲染
        setNotebooks(fetchedNotebooks);
        setError(null);
      } catch (err) {
        setError('加载笔记本数据失败');
        console.error(err);
      } finally {
        setIsLoading(false);
      }
    };

    fetchNotebooks();
  }, []); // 空依赖数组,确保仅在组件挂载时执行一次

  // 在JSX中使用状态数据
  if (isLoading) return <div>加载中...</div>;
  if (error) return <div>错误:{error}</div>;

  return (
    <div>
      <h2>笔记本列表</h2>
      <ul>
        {notebooks.map(([notebook, withdraws], index) => (
          <li key={index}>
            <p>序列号:{notebook.numSerie}</p>
            <p>状态:{notebook.isActive ? '活跃' : '非活跃'}</p>
            <p>提取记录:{withdraws.length}条</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

2. 结合全局Provider方案(适配你的现有代码)

从你提供的withdraw_provider代码来看,你已在使用React Context做全局状态管理,组件需订阅Context中的状态:

第一步:修正Provider的Context定义

确保你的Context包含完整的状态与方法:

import { createContext, useContext, useState, ReactNode } from 'react';

interface WithdrawContextType {
  notebooks: [Notebook, Withdraw[]][];
  getAllNotebooks: (idToken: string) => Promise<void>;
  error: string | null;
  isLoading: boolean;
}

const WithdrawContext = createContext<WithdrawContextType | undefined>(undefined);

export function WithdrawProvider({ children }: { children: ReactNode }) {
  const [notebooks, setNotebooks] = useState<[Notebook, Withdraw[]][]>([]);
  const [error, setError] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(false);

  async function getAllNotebooks(idToken: string){
    try {
      setIsLoading(true);
      const notebooks = await getAllNotebooksUsecase.execute(idToken);
      setNotebooks(notebooks);
      setError(null);
    } catch (error: any) {
      console.log(`ERROR PROVIDER: ${error}`);
      setError(error.message);
      setNotebooks([]);
    } finally {
      setIsLoading(false);
    }
  }

  return (
    <WithdrawContext.Provider value={{ notebooks, getAllNotebooks, error, isLoading }}>
      {children}
    </WithdrawContext.Provider>
  );
}

// 自定义Hook,简化组件调用Context的逻辑
export function useWithdraw() {
  const context = useContext(WithdrawContext);
  if (!context) {
    throw new Error('useWithdraw必须在WithdrawProvider内部使用');
  }
  return context;
}

第二步:在组件中使用Context

import { useEffect } from 'react';
import { useWithdraw } from './path/to/withdraw-provider';

function NotebookList() {
  const { notebooks, getAllNotebooks, error, isLoading } = useWithdraw();

  useEffect(() => {
    const fetchData = async () => {
      const idToken = await getIdToken();
      await getAllNotebooks(idToken);
    };

    fetchData();
  }, [getAllNotebooks]);

  if (isLoading) return <div>加载中...</div>;
  if (error) return <div>错误:{error}</div>;

  return (
    <div>
      <h2>笔记本列表</h2>
      <ul>
        {notebooks.map(([notebook, withdraws], idx) => (
          <li key={idx}>
            <strong>序列号:{notebook.numSerie}</strong>
            <p>是否活跃:{notebook.isActive ? '是' : '否'}</p>
            <div>
              <h4>提取记录:</h4>
              {withdraws.map((withdraw, wIdx) => (
                <div key={wIdx}>
                  <p>邮箱:{withdraw.email}</p>
                  <p>提取时间:{new Date(withdraw.withdrawTime).toLocaleString()}</p>
                </div>
              ))}
            </div>
          </li>
        ))}
      </ul>
    </div>
  );
}

额外代码修正建议

  1. 修正请求头错误:withdraw_repository_http中Authorization头末尾多了一个单引号,应改为Bearer ${idToken},否则会导致授权失败。
  2. 补全useEffect语法:原useEffect缺少闭合括号,正确写法为}, []);。
  3. 修复Provider中的错误逻辑:原代码中const setError = error; setError(setError);属于重复命名且逻辑错误,改为setError(error.message);即可。

内容的提问来源于stack exchange,提问作者Luigi Trevisan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:10:18