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

Next.js+TS异步组件返回Promise<Element>非合法JSX报错问询

报错根因
  • 组件入参写法错误:React组件的第一个入参固定为props对象,你直接将id: string设为组件入参,JSX调用组件时默认传入的是空props对象{},因此触发Type '{}' is not assignable to type 'string'类型错误。
  • 客户端组件不支持async声明:给组件加async关键字后,返回值会变为Promise<JSX.Element>,而合法JSX元素必须是同步返回的ReactElement类型,因此触发组件无法作为JSX组件使用的报错。手动通过类型标注强转Promise类型无法解决问题,这是React运行时的硬性校验规则,不是单纯的TS类型问题。
  • 附带逻辑bug:原有getItemData函数中(await itemData).json()的返回值是Promise,缺少await会导致最终拿到的是Pending状态的Promise对象,不是实际接口返回数据。
修复方案

根据你使用Next.js的渲染模式选对应方案即可。

方案1:客户端组件(兼容Pages Router、App Router加了'use client'的组件)

客户端组件不能声明为async,数据请求需要放到副作用函数中,同时修正props入参写法,补全类型定义:

// App Router客户端组件需要加下面这行,Pages Router删除即可
'use client';
import { useEffect, useState } from 'react';
// 替换成你项目内的组件实际引入路径
import Button from '@/components/Button';
import ItemContent from '@/components/ItemContent';

// 定义组件props类型
type ItemProps = {
  id: string;
}

const Item = ({ id }: ItemProps) => {
  // 初始化状态,可加默认加载态
  const [itemData, setItemData] = useState<{name: string; description: string}>({
    name: '加载中',
    description: '正在获取商品信息...'
  });

  useEffect(() => {
    const fetchData = async () => {
      try {
        const data = await getItemData(id);
        setItemData(data);
      } catch (err) {
        setItemData({
          name: 'Error',
          description: "Couldn't fetch the latest items :( ..."
        })
      }
    };
    fetchData();
  }, [id]);

  return (
    <Button className="item">
      <ItemContent name={itemData.name} description={itemData.description} />
    </Button>
  );
};

同步修正getItemData函数的逻辑,补全await和类型定义:

async function getItemData(item: string): Promise<{name: string; description: string}> {
  if (item === "") {
    return {
      name: "Error",
      description: "Couldn't fetch the latest items :( ..."
    }
  }

  try {
    const res = await fetch("/api/items/getItem/", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ id: item })
    });
    if (!res.ok) throw new Error('Request failed');
    // 补全await,等待json解析完成
    return await res.json();
  } catch (err) {
    console.error(err);
    throw new Error("Failed to get item data");
  }
}

方案2:Next.js App Router 服务端组件

如果你使用App Router的服务端组件,可以直接用async写法,但必须遵守组件入参规则,第一个参数为props对象:

// 服务端组件不能加'use client',也不能使用useEffect、useState等客户端hook
// 替换成你项目内的组件实际引入路径
import Button from '@/components/Button';
import ItemContent from '@/components/ItemContent';

type ItemProps = {
  id: string;
}

// 服务端组件支持async声明
const Item = async ({ id }: ItemProps) => {
  const itemData = await getItemData(id);
  return (
    <Button className="item">
      <ItemContent name={itemData.name} description={itemData.description} />
    </Button>
  );
};

注意:服务端组件只能在服务端组件树中直接使用,若要传给客户端组件作为children,需要先在服务端渲染完成后再传入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 08:12:11