在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
相关产品推荐
相关产品推荐

