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

使用Prisma与PostgreSQL时hobbies不可迭代错误排查

问题描述

我是Prisma和React新手,PostgreSQL数据库能正常运行,想在应用里展示存储的数据。我的schema里Hobby模型如下:

model Hobby {
  id        Int  @id @default(autoincrement())
  title     String
}

我用useContext分发createHobby功能,上下文文件代码如下:

export async function getServerSideProps() {
    const hobbies: Prisma.HobbyUncheckedCreateInput[] = await prisma.hobby.findMany();
    return {
        props: {initialHobbies: hobbies},
    };
}

export const HobbyContext = createContext({})
function Provider({ children, initialHobbies }){

    const [hobbies, setHobbies] = useState<Prisma.HobbyUncheckedCreateInput[]>(initialHobbies);

    const createHobby = async (title) => {

        const body: Prisma.HobbyCreateInput = {
            title,

        };
        await fetcher("/api/create-hobby", {hobby : body});
        console.log(hobbies);

        const updatedHobbies = [
            ...hobbies,
            body
        ];
        setHobbies(updatedHobbies);

    const contextData = {
        hobbies,
        createHobby,

    }
    return (
        <HobbyContext.Provider value={contextData}>
            {children}
        </HobbyContext.Provider>
    );
};

export default HobbyContext;
export {Provider};

现在出现错误:Uncaught (in promise) TypeError: hobbies is not iterable at createHobby,指向代码const updatedHobbies = [...hobbies, body];。

另外我有个HobbyCreate.tsx组件,通过表单提交创建展示hobby标题的卡片,代码如下:

function HobbyCreate({updateModalState}) {
    const [title, setTitle] = useState('');
    const {createHobby} = useHobbiesContext();
    
    const handleChange = (event) => {
        setTitle(event.target.value)
    };

    const handleSubmit = (event) => {
        event.preventDefault();
        createHobby(title);
    };
    return (
        ...
        <form onSubmit={handleSubmit}></form>
        ...

    )

我不确定问题出在哪,怀疑是创建const [hobbies, setHobbies]并使用initialHobbies时出了问题。


错误分析与修复方案

核心原因

hobbies is not iterable表明你尝试展开的hobbies不是数组类型,可能的触发点:

  • initialHobbies初始值不是数组(比如查询失败返回null/undefined)
  • Context默认值为空对象,组件在Provider外调用时拿到undefined的hobbies
  • 代码存在语法错误(比如createHobby函数未闭合大括号)

具体修复步骤

  1. 兜底initialHobbies的数组类型
    在Provider组件给initialHobbies设置默认空数组,避免传入非数组值:

    function Provider({ children, initialHobbies = [] }){
        const [hobbies, setHobbies] = useState<Prisma.HobbyUncheckedCreateInput[]>(initialHobbies);
        // 后续代码
    }
    

    同时在getServerSideProps里增加错误捕获,确保返回数组:

    export async function getServerSideProps() {
        try {
            const hobbies = await prisma.hobby.findMany();
            return { props: { initialHobbies: hobbies || [] } };
        } catch (err) {
            console.error(err);
            return { props: { initialHobbies: [] } };
        }
    }
    
  2. 修正Context默认值结构
    给Context设置符合业务逻辑的默认值,避免组件误用时报错:

    export const HobbyContext = createContext<{
        hobbies: Prisma.HobbyUncheckedCreateInput[];
        createHobby: (title: string) => Promise<void>;
    }>({
        hobbies: [],
        createHobby: async () => {}
    })
    
  3. 修复状态更新与语法错误

    • 补上createHobby缺失的闭合大括号,避免语法错误
    • 使用函数式更新获取最新状态,避免闭包导致的旧值问题:
    const createHobby = async (title) => {
        const body: Prisma.HobbyCreateInput = { title };
        await fetcher("/api/create-hobby", { hobby: body });
        // 函数式更新确保拿到最新的hobbies状态
        setHobbies(prevHobbies => [...prevHobbies, body]);
    }; // 补上这个闭合大括号
    
  4. 完善自定义Hook的校验
    确保useHobbiesContext只能在Provider内部使用:

    export function useHobbiesContext() {
        const context = useContext(HobbyContext);
        if (!context) {
            throw new Error("useHobbiesContext必须在HobbyContext.Provider内部使用");
        }
        return context;
    }
    

额外建议

  • 开发时查看console.log(hobbies)的输出,确认它的实际类型,快速定位问题
  • 给所有状态和Context值加上严格的TypeScript约束,提前发现类型不匹配问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 16:25:35