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

Next.js TypeScript动态路由获取单篇文章返回Undefined求助

Next.js TypeScript 单篇文章页面 undefined 问题排查与解决

问题概述

使用Next.js TypeScript搭建博客,已实现从MongoDB获取所有文章,但单篇文章页面无法正常加载,控制台打印singlePost为undefined。API接口测试正常,此前Next.js JavaScript版本可正常运行,且.env中apiDomain配置正确。

核心问题分析与修复步骤

1. API路由路径与参数解构错误

你的route.ts注释标注为GET /api/posts,但单篇文章的API路由应对应/api/posts/[id],因此文件需放在app/api/posts/[id]/route.ts路径下。同时,Next.js 13+的API路由函数需要正确解构params并添加类型定义,否则会导致params.id无法正确获取。

修改后的route.ts:

import { connectDB } from "@/database/dbConfig";
import Post from "@/models/postModel";
import { NextRequest, NextResponse } from "next/server";

// GET /api/posts/[id]
export const GET = async (request: NextRequest, { params }: { params: { id: string } }) => {
  try {
    await connectDB();

    const post = await Post.findById(params.id);

    if (!post) return NextResponse.json({ message: "Post Not Found" }, { status: 404 });
    return NextResponse.json(post, { status: 200 });
  } catch (error) {
    console.error(error);
    return NextResponse.json({ message: "Something went wrong" }, { status: 500 });
  }
};

2. 组件中useEffect触发条件错误

初始状态下singlePost是undefined,但你的判断条件是if (singlePost === null),导致组件挂载时不会触发数据请求。同时,数据请求开始时未设置loading为true,逻辑不完整。

修改后的SinglePostPage组件:

import { useParams } from "next/navigation";
import { useState, useEffect } from "react";
import fetchSinglePost from "@/utils/fetchSinglePost";
// 假设你有Post类型定义
import type Post from "@/models/postModel";

const SinglePostPage = () => {
  const { id } = useParams();
  const [singlePost, setSinglePost] = useState<Post | undefined>(undefined);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchPost = async () => {
      if (!id) return;
      setLoading(true);
      try {
        const postData = await fetchSinglePost(id as string);
        setSinglePost(postData);
      } catch (error) {
        console.error("Error fetching post:", error);
      } finally {
        setLoading(false);
      }
    };

    // 当id存在且singlePost未加载时触发请求
    if (id && !singlePost) {
      fetchPost();
    }
  }, [id, singlePost]);

  if (loading) return <div>Loading...</div>;
  if (!singlePost) return <div>Post not found</div>;

  return (
    <div className="singlepostPage">
      <h2>{singlePost.title}</h2>
      <div>{singlePost.content}</div>
    </div>
  );
};

export default SinglePostPage;

3. 确保apiDomain正确暴露给客户端

客户端组件中无法直接读取未加NEXT_PUBLIC_前缀的环境变量,需确保.env中的变量名为NEXT_PUBLIC_API_DOMAIN,并在fetchSinglePost中正确引用:

修改后的fetchSinglePost函数:

import type Post from "@/models/postModel";

const apiDomain = process.env.NEXT_PUBLIC_API_DOMAIN;

async function fetchSinglePost(id: string): Promise<Post> {
  try {
    if (!apiDomain) {
      throw new Error("API domain not configured");
    }

    const res = await fetch(`${apiDomain}/api/posts/${id}`);

    if (!res.ok) {
      throw new Error(`Failed to fetch post: ${res.statusText}`);
    }

    return await res.json();
  } catch (error) {
    console.error("Fetch single post error:", error);
    throw error;
  }
}

export default fetchSinglePost;

额外检查点

  • 确认MongoDB中的_id是字符串类型,或者在查询时正确处理ObjectId(如果你的postModel中_id定义为ObjectId,需确保传入的id能被findById识别)。
  • 检查网络请求是否真的发送(通过浏览器开发者工具的Network标签),确认请求URL和参数是否正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 20:13:14