Next.js项目中TypeError: Cannot read properties of undefined (reading 'Link')错误排查求助
Next.js项目中TypeError: Cannot read properties of undefined (reading 'Link')错误排查求助
我正在开发一个Next.js项目,逻辑是如果用户浏览器本地存储里有profile信息,就创建一个唯一ID并跳转到对应的聊天室链接,但一直遇到错误,试过各种方法包括问ChatGPT都没解决,希望大家帮忙看看。
相关代码
create-profile/page.tsx
"use client"; import Setup from "@/components/Setup"; import { useRouter } from "next/navigation"; import { useEffect } from "react"; import createUniqueLinkId from "@/libs/createlink"; const Page = () => { const router = useRouter(); interface Profile { userName: string; avatar: number; } useEffect(() => { const profileFromLocalStorage = localStorage.getItem("profile"); const profile: Profile | null = profileFromLocalStorage ? (JSON.parse(profileFromLocalStorage) as Profile) : null; const redirectOrSetup = async () => { if (profile) { try { const chatRoomLink = await createUniqueLinkId(); router.push(`/chatroom/${chatRoomLink}`); } catch (error) { console.error("Failed to create chat room link", error); } } }; redirectOrSetup(); }, []); return ( <div className="lg:mt-32 mt-8"> <Setup /> </div> ); }; export default Page;
createlink.ts
import { v4 as uuidv4 } from "uuid"; import Link from "@/model/link"; import mongoose from "mongoose"; import { connectToDB } from "@/utils/database"; export const createUniqueLinkId = async (): Promise<string> => { let linkId = ""; let isUnique = false; try { await connectToDB(); console.log(Link) while (!isUnique) { linkId = uuidv4(); const existingLink = await Link.findOne({ linkId }); if (!existingLink) { isUnique = true; } } const newLink = new Link({ linkId }); await newLink.save(); return linkId; } catch (error) { console.error("Error creating unique link ID:", error); throw new Error("Failed to create a unique link ID"); } }; export default createUniqueLinkId;
link模型代码
import mongoose, { Document, Model, Schema } from 'mongoose'; export interface ILink extends Document { linkId: string, participants: string[]; createdAt: Date; } const linkSchema = new Schema<ILink>({ linkId:{ type: String, required: true, unique: true, }, participants: { type: [String], default: [], }, createdAt: { type: Date, default: Date.now, }, }, { timestamps: true }); const Link: Model<ILink> = mongoose.models.Link || mongoose.model<ILink>('Link', linkSchema); export default Link;
MongoDB连接代码
"use server" import mongoose from "mongoose"; let isConnected: boolean = false; // Connect to MongoDB export const connectToDB = async (): Promise<void> => { if (isConnected) { console.log('MongoDB is already connected'); return; } try { await mongoose.connect(process.env.MONGODB_URI as string, { dbName: "anonymous_project" }); isConnected = true; console.log('MongoDB connection is successful'); } catch (error) { if (error instanceof Error) { throw new Error(`MongoDB connection failed: ${error.message}`); } else { throw new Error('MongoDB connection failed with an unknown error'); } } };
问题分析与解决方案
核心问题
从错误TypeError: Cannot read properties of undefined (reading 'Link')和代码结构来看,问题出在客户端组件直接执行了服务端专属的数据库操作:
- 你的
page.tsx是标记"use client"的客户端组件,在浏览器环境运行,但它直接调用了createUniqueLinkId函数 - 这个函数依赖
mongoose操作MongoDB,而mongoose是服务端库,浏览器环境中既没有初始化mongoose,也不允许直接连接数据库,所以mongoose.models是undefined,访问mongoose.models.Link就会抛出上述错误 - 另外,标记
"use server"的connectToDB函数也不能在客户端环境被调用
修复方案:将数据库操作移到服务端执行
所有涉及数据库的逻辑必须放在服务端运行,我们可以通过Server Action或API路由来实现:
方案1:使用Next.js Server Action(推荐,App Router适配)
- 改造
createlink.ts,添加"use server"标记,将其转为Server Action:
"use server"; // 标记为服务端执行的函数 import { v4 as uuidv4 } from "uuid"; import Link from "@/model/link"; import mongoose from "mongoose"; import { connectToDB } from "@/utils/database"; export const createUniqueLinkId = async (): Promise<string> => { let linkId = ""; let isUnique = false; try { await connectToDB(); while (!isUnique) { linkId = uuidv4(); const existingLink = await Link.findOne({ linkId }); if (!existingLink) { isUnique = true; } } const newLink = new Link({ linkId }); await newLink.save(); return linkId; } catch (error) { console.error("Error creating unique link ID:", error); throw new Error("Failed to create a unique link ID"); } }; export default createUniqueLinkId;
- 客户端组件调用方式不变,但确保Next.js版本支持Server Action(13.4+),并且在
next.config.js中启用相关配置。
方案2:使用API路由(兼容所有Next.js版本)
- 创建
app/api/create-link/route.ts服务端路由:
import { NextResponse } from "next/server"; import { v4 as uuidv4 } from "uuid"; import Link from "@/model/link"; import { connectToDB } from "@/utils/database"; export async function GET() { try { await connectToDB(); let linkId = ""; let isUnique = false; while (!isUnique) { linkId = uuidv4(); const existingLink = await Link.findOne({ linkId }); if (!existingLink) { isUnique = true; } } const newLink = new Link({ linkId }); await newLink.save(); return NextResponse.json({ linkId }, { status: 200 }); } catch (error) { console.error("Error creating unique link ID:", error); return NextResponse.json( { error: "Failed to create a unique link ID" }, { status: 500 } ); } }
- 修改客户端组件的调用逻辑:
const redirectOrSetup = async () => { if (profile) { try { const res = await fetch("/api/create-link"); if (!res.ok) throw new Error("Failed to fetch link ID"); const data = await res.json(); router.push(`/chatroom/${data.linkId}`); } catch (error) { console.error("Failed to create chat room link", error); } } };
额外注意事项
- 永远不要在客户端组件中直接操作数据库或使用服务端专属库
- 可以给
useEffect的依赖数组添加profile,确保逻辑的响应性 - 对
localStorage的JSON解析结果可以增加异常捕获,避免格式错误导致的崩溃
备注:内容来源于stack exchange,提问作者Gideon Olaiya
相关产品推荐
相关产品推荐

