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

自定义React Hook异步API调用返回Promise而非目标字符串的问题求助

自定义React Hook异步API调用返回Promise而非目标字符串的问题求助

问题分析

你遇到这个问题的核心原因很明确:async 函数本身会自动把返回值包装成 Promise,而你在 useMemo 里用了 async 回调,所以最终 accesToken 变量本质上就是一个 Promise 对象,而非你期望的字符串值。另外还要注意,useMemo 的设计初衷是缓存同步计算的结果,并不适合处理异步请求这类副作用操作。

正确的解决方案

我们应该用 React 的 useState 来管理异步请求的结果,搭配 useEffect 触发和处理异步操作——这是 React 中处理异步请求的标准范式。下面是修改后的 Hook 代码:

import { useState, useEffect } from "react";

export const useGetPaymentIntent = (userId: string) => {
  // 存储获取到的token
  const [accessToken, setAccessToken] = useState<string | null>(null);
  // 存储加载状态,方便UI做加载提示
  const [isLoading, setIsLoading] = useState(true);
  // 存储错误信息,处理请求失败的情况
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    // 定义异步请求函数
    const fetchToken = async () => {
      try {
        setIsLoading(true);
        const response = await fetch("https://example.com/get-token", {
          method: "POST",
          headers: {
            // 修复了环境变量的模板字符串写法,之前的写法会把变量名当成字面量
            Authorization: `Bearer ${process.env.REACT_APP_KEY}`,
            "Content-Type": "application/x-www-form-urlencoded"
          },
          body: new URLSearchParams({
            userId: userId
          })
        });

        if (!response.ok) {
          throw new Error(`请求失败:${response.status}`);
        }

        const data = await response.json();
        setAccessToken(data.access_token);
        setError(null);
      } catch (err) {
        setError(err instanceof Error ? err.message : "未知错误");
        setAccessToken(null);
      } finally {
        setIsLoading(false);
      }
    };

    // 调用异步函数
    fetchToken();
  }, [userId]); // 依赖userId,当userId变化时重新发起请求

  // 返回状态和结果,方便组件中灵活使用
  return { accessToken, isLoading, error };
};

组件中使用示例

在你的业务组件里可以这样调用这个 Hook:

import { useGetPaymentIntent } from "./path-to-your-hook";

const PaymentComponent = ({ userId }) => {
  const { accessToken, isLoading, error } = useGetPaymentIntent(userId);

  if (isLoading) {
    return <div>正在获取支付令牌...</div>;
  }

  if (error) {
    return <div>获取失败:{error}</div>;
  }

  return <div>支付令牌:{accessToken}</div>;
};

额外补充说明

  1. 为什么不用 useMemo?因为 useMemo 是用于同步计算结果的缓存,异步操作属于副作用范畴,交给 useEffect 处理才是符合 React 设计理念的做法。
  2. 加入加载和错误状态是为了让你的UI更健壮,用户能清晰感知请求的进展和异常情况。
  3. 顺便修复了你代码里的一个小bug:之前 Authorization 头的写法没有正确插入环境变量,会导致请求携带的令牌无效。

备注:内容来源于stack exchange,提问作者youssefrag

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 11:38:03