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

Next.js 13+TypeScript异步组件获取数据时JSX组件类型错误求助

解决Next.js 13 + TypeScript异步组件Filter的JSX类型错误

错误的核心原因很明确:你把Filter组件写成了async函数,导致它的返回值是Promise<JSX.Element>,但React要求组件必须返回ReactElement(即JSX元素)或null,TypeScript因此抛出类型不匹配的错误。

下面分场景给出解决方案:

方案1:App Router下的Server Component(无交互需求)

如果你的Filter组件仅用于展示分类、不需要用户交互,可以直接利用Next.js 13 App Router对Server Component的原生异步支持,无需额外处理:

// app/components/Filter.tsx
import api from '@/lib/api';

// Server Component 允许直接定义为async函数
async function Filter() {
  const categories = await api.get('/categories/');
  
  return (
    <div className="filter-container">
      {categories.map(category => (
        <div key={category.id} className="filter-item">
          {category.name}
        </div>
      ))}
    </div>
  );
}

export default Filter;

注意:Server Component不能使用React Hooks(如useState、useEffect),如果需要交互功能,使用下面的方案。

方案2:App Router/Pages Router下的Client Component(有交互需求)

如果组件需要交互(比如点击筛选、切换状态),必须用useEffect结合状态来处理异步请求,不能直接把组件定义为async函数:

// 适用于app目录(需加'use client')或pages目录的组件
'use client'; // App Router下必须添加这行,Pages Router可省略

import { useState, useEffect } from 'react';
import api from '@/lib/api';

// 定义分类类型,满足TypeScript类型校验需求
type Category = {
  id: number;
  name: string;
};

function Filter() {
  const [categories, setCategories] = useState<Category[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [errorMsg, setErrorMsg] = useState<string | null>(null);

  // 组件挂载后发起异步请求
  useEffect(() => {
    const fetchCategories = async () => {
      try {
        const data = await api.get('/categories/');
        setCategories(data);
      } catch (err) {
        setErrorMsg('分类加载失败,请稍后重试');
      } finally {
        setIsLoading(false);
      }
    };

    fetchCategories();
  }, []);

  // 处理加载、错误状态
  if (isLoading) return <div>加载中...</div>;
  if (errorMsg) return <div className="text-red-500">{errorMsg}</div>;

  return (
    <div className="filter-wrapper">
      <h4>筛选分类</h4>
      {categories.map(category => (
        <label key={category.id} className="flex items-center gap-2">
          <input type="checkbox" value={category.id} />
          <span>{category.name}</span>
        </label>
      ))}
    </div>
  );
}

export default Filter;

额外优化:用数据请求库简化逻辑

如果项目中有多个异步请求场景,推荐使用React Query或SWR这类库替代useEffect+state,代码更简洁,还自带缓存、重试、自动刷新等功能:

'use client';

import { useQuery } from '@tanstack/react-query';
import api from '@/lib/api';

type Category = { id: number; name: string };

function Filter() {
  const { data: categories, isLoading, error } = useQuery({
    queryKey: ['categories'],
    queryFn: () => api.get('/categories/'),
  });

  if (isLoading) return <div>加载中...</div>;
  if (error) return <div>加载失败</div>;

  return (
    <div className="filter-wrapper">
      <h4>筛选分类</h4>
      {categories?.map(category => (
        <label key={category.id} className="flex items-center gap-2">
          <input type="checkbox" value={category.id} />
          <span>{category.name}</span>
        </label>
      ))}
    </div>
  );
}

export default Filter;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 15:10:39