Next.js 13从Supabase取数建图片画廊遇‘Result is not iterable’错误
解决Next.js 13 App目录中generateStaticParams的“Result is not iterable”错误
你遇到的核心问题是用错了generateStaticParams的用途,这个函数不是用来替代getStaticProps传递页面数据的,而是专门给动态路由预生成路由参数的。App目录下获取静态数据的正确方式是直接在页面组件中使用async/await。
错误原因拆解
generateStaticParams的返回值要求是可迭代的参数数组(比如[{ id: 1 }, { id: 2 }]),用于生成动态路由的所有可能路径。但你现在返回的是类似getStaticProps的{ props: { ... } }对象,完全不符合该函数的要求,所以抛出“Result is not iterable”错误。
同时,App目录不再支持getStaticProps/getServerSideProps,所有数据获取逻辑需要放在组件内部或单独的异步函数中。
修正后的代码实现
1. 页面组件(app/products/page.tsx)
移除错误的generateStaticParams,改为在组件内异步获取数据,同时补充类型定义:
import { createClient } from '@supabase/supabase-js'; import Gallery from '@/components/Gallery'; // 定义匹配Supabase表结构的Image类型 type Image = { id: number; imageSrc: string; // 根据你的实际表结构补充其他字段 }; // 封装Supabase客户端初始化(可抽离到utils文件复用) const getSupabaseAdmin = () => { return createClient( process.env.NEXT_PUBLIC_SUPABASE_URL || '', process.env.SUPABASE_SERVICE_ROLE_KEY || '' ); }; // 页面组件改为async函数,直接在内部获取数据 export default async function ProductsPage() { const supabaseAdmin = getSupabaseAdmin(); // 给data设置默认空数组,避免返回null时map报错 const { data: images = [] } = await supabaseAdmin.from('images').select('*').order('id'); return ( <div> <Gallery images={images} /> </div> ); }
2. Gallery组件(components/Gallery.tsx)
确保类型引用正确:
import BlurImage from './BlurImage'; // 导入Image类型,也可以把类型放到公共文件(如types/index.ts)统一管理 import type { Image } from '@/app/products/page'; export default function Gallery({ images }: { images: Image[] }) { return ( <div className="mx-auto max-w-2xl py-16 px-4 sm:py-24 sm:px-6 lg:max-w-7xl lg:px-8"> <div className="grid grid-cols-1 gap-y-10 gap-x-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8"> {images.map((image) => ( <BlurImage key={image.id} image={image} /> ))} </div> </div> ); }
3. BlurImage组件(components/BlurImage.tsx)
更新Image类型引用,并适配Next.js 13的Image组件API:
'use client'; import Image from 'next/image'; import { useState } from 'react'; import type { Image } from '@/app/products/page'; function cn(...classes: string[]) { return classes.filter(Boolean).join(' '); } function BlurImage({ image }: { image: Image }) { const [isLoading, setLoading] = useState(true); return ( <div className="group"> <div className="aspect-w-1 aspect-h-1 w-full overflow-hidden rounded-lg bg-gray-200 xl:aspect-w-7 xl:aspect-h-8"> <Image alt="画廊图片" // 补充有意义的alt文本,提升可访问性 src={image.imageSrc} fill // Next.js 13+推荐使用fill替代layout="fill" objectFit="cover" className={cn( 'duration-700 ease-in-out group-hover:opacity-75', isLoading ? 'scale-110 blur-2xl grayscale' : 'scale-100 blur-0 grayscale-0' )} onLoadingComplete={() => setLoading(false)} /> </div> </div> ); } export default BlurImage;
关键注意事项
- App目录下的页面组件支持直接写成async函数,Next.js会在构建时自动执行数据获取逻辑(默认静态渲染),无需额外配置
- generateStaticParams仅用于动态路由场景(比如
app/products/[id]/page.tsx),返回格式为[{ param1: 'value1' }, ...],用来预生成所有可能的路由路径 - 始终处理Supabase返回的
data可能为null的情况,给默认空数组避免后续map操作报错 - 补充TypeScript类型定义可以提前发现潜在错误,提升代码健壮性
内容的提问来源于stack exchange,提问作者Wizwoke
相关产品推荐
相关产品推荐

