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

在useEffect中使用异步函数:不使用.then()获取[[PromiseResult]]

问题与解决方案

问题

在React组件的useEffect中尝试获取Firebase用户idToken,将其作为Authorization请求头从服务器拉取数据,再用数据填充Highcharts选项并渲染图表。目前的问题是无法获取到token的实际值,拿到的是完整的Promise对象;如果用.then()会导致大量代码重复,因为认证和未认证场景下,请求头构建与数据获取逻辑大部分重合。

解决方案

核心思路是将useEffect内部逻辑封装为异步函数,统一处理token获取逻辑,避免代码分支重复,同时确保拿到token的实际值而非Promise:

  • 将useEffect的回调逻辑包装为异步函数(注意useEffect不能直接返回async函数,需内部定义后调用)
  • 统一获取token:存在currentUser时异步获取token,否则使用"unauthorized"
  • 基于拿到的实际token构建请求头
  • 正确更新React状态,避免直接修改状态对象

修改后的完整代码:

import React, { useState, useEffect } from "react";
import Highcharts from "highcharts/highstock";
import HighchartsReact from "highcharts-react-official";
import { useAuth } from "../../../contexts/AuthContext";
import ChartLoadingScreen from '../ChartLoadingScreen';

// 将主题定义移到组件外,避免每次渲染重复创建
const HighchartsTheme = {
  title: {
    text: undefined,
  },
  series: [],
  accessibility: {
    enabled: false
  },
  yAxis: [{
    opposite: true,
    type: 'linear',
    labels: {
      align: 'right',
    },
  },
  {
    opposite: false,
    type: 'logarithmic',
  }]
};

export default function MyChart({ chartDataEndpoint }) {
  const [isMounted, setMounted] = useState(false);
  const [options, setOptions] = useState(HighchartsTheme);
  const { currentUser } = useAuth();

  useEffect(() => {
    // 定义异步处理函数
    const fetchDataAndUpdateChart = async () => {
      setMounted(false);
      let idToken;
      // 统一处理token获取逻辑
      if (currentUser) {
        idToken = await currentUser.getIdToken(/* forceRefresh */ true);
      } else {
        idToken = "unauthorized";
      }

      // 构建请求头
      const headers = new Headers();
      headers.append('authorization', idToken);

      try {
        // 并行发起请求
        const responses = await Promise.all([
          fetch("https://my-server-side/data1"),
          fetch("https://my-server-side/data2", { headers })
        ]);
        // 解析响应数据
        const data = await Promise.all(responses.map(res => res.json()));
        
        // 正确更新图表配置,使用函数式更新避免直接修改状态
        setOptions(prevOptions => ({
          ...prevOptions,
          series: [
            { data: data[0], yAxis: 1 },
            { data: data[1], yAxis: 0 }
          ]
        }));
        setMounted(true);
      } catch (err) {
        console.error('数据获取失败:', err);
        // 可在此添加错误提示等处理逻辑
      }
    };

    fetchDataAndUpdateChart();

    return () => {
      setMounted(false);
      setOptions(HighchartsTheme);
    };
  }, [currentUser, chartDataEndpoint]); // 添加currentUser到依赖数组,用户状态变化时重新请求

  return (
    <>
      {isMounted ? (
        <div>
          <HighchartsReact
            highcharts={Highcharts}
            constructorType={"stockChart"}
            options={options}
          />
        </div>
      ) : (
        <ChartLoadingScreen isDefault={true} />
      )}
    </>
  );
}

关键优化点说明

  • 解决Promise对象问题:通过await直接获取token的实际值,而非返回Promise对象传入请求头
  • 消除代码重复:将token获取逻辑统一处理,认证/未认证场景共享后续的请求与图表更新逻辑
  • 正确更新状态:使用函数式更新setOptions(prev => ...),避免直接修改状态对象,确保状态更新触发组件重渲染
  • 完善依赖数组:添加currentUser到依赖项,确保用户登录/登出时重新拉取数据
  • 错误处理:添加try/catch捕获请求错误,便于调试和后续错误提示开发

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 10:01:24