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

Next.js集成Firestore获取详情报错:doc()路径为空

问题原因与解决方案

核心原因

  1. Next.js App Router路由参数获取方式错误:你使用的是App Router(useRouter来自next/navigation),但仍沿用Pages Router的router.query来获取动态路由参数。在App Router中,动态路由(如/movie/[id])的参数需通过页面组件的props直接接收params,而非依赖router.query;且router.query在App Router初始加载时会是undefined,因为客户端组件需要等待路由状态稳定后才能拿到参数。
  2. Firebase初始化重复冗余:详情页和列表页都在useEffect里重复初始化Firebase,应直接导入你在firebase.js中配置好的db实例,避免重复初始化的潜在问题。
  3. 缺少参数存在性校验:调用Firestore的doc()前未检查id是否存在,空ID直接触发了Function doc() cannot be called with an empty path错误。

修复步骤

1. 修改详情页,通过props获取动态路由参数

确保详情页文件路径为app/movie/[id]/page.js,然后修改组件代码:

"use client";

import React, { useState, useEffect } from "react";
import { doc, getDoc } from "firebase/firestore";
import db from "../../firebase"; // 直接导入已初始化的db

const MovieDetail = ({ params }) => { // 接收动态路由参数props
  const [movieDetails, setMovieDetails] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchMovieDetails = async () => {
      // 先校验ID是否有效
      if (!params.id) {
        setError("无效的电影ID");
        return;
      }

      setIsLoading(true);
      setError(null);

      try {
        const docRef = doc(db, "movies", params.id);
        const docSnap = await getDoc(docRef);

        if (docSnap.exists()) {
          setMovieDetails(docSnap.data());
        } else {
          setError("未找到该电影");
        }
      } catch (error) {
        console.error("获取电影详情失败:", error);
        setError("获取电影详情失败: " + error.message);
      } finally {
        setIsLoading(false);
      }
    };

    fetchMovieDetails();
  }, [params.id]); // 依赖params.id监听变化

  return (
    <div>
      {isLoading ? (
        <p>加载中...</p>
      ) : error ? (
        <p>{error}</p>
      ) : movieDetails ? (
        <h1>{movieDetails.title}</h1>
      ) : (
        <p>无电影信息</p>
      )}
    </div>
  );
};

export default MovieDetail;

2. 优化列表页的Firebase使用

移除列表页中重复的Firebase初始化代码,直接导入已配置的db:

"use client";

import React, { useState, useEffect } from "react";
import { collection, getDocs } from "firebase/firestore";
import Image from "next/image";
import Link from "next/link";
import db from "../firebase"; // 导入已初始化的db
import Search from "@/components/Search/Search";
import "./s.css";

const Page = () => {
  const [movies, setMovies] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      try {
        console.log("开始获取数据...");
        const moviesCollection = await getDocs(collection(db, "movies"));

        const moviesData = moviesCollection.docs.map((doc) => ({
          id: doc.id,
          ...doc.data(),
        }));

        setMovies(moviesData);
        console.log("数据获取成功:", moviesData);
      } catch (error) {
        console.error("获取数据失败:", error);
      }
    };

    fetchData();
  }, []);

  return (
    <div>
      <Search />
      <main>
        <div className="hero-container">
          {movies.map((movie) => (
            <div key={movie.id} className="main-container">
              <div className="poster-container">
                <Link href={`/movie/${movie.id}`}>
                  <Image
                    src={movie.posterUrl}
                    className="poster"
                    width={230}
                    height={350}
                    alt={movie.title}
                  />
                  <p>
                    {movie.title} ({movie.year})
                  </p>
                </Link>
              </div>
            </div>
          ))}
        </div>
      </main>
    </div>
  );
};

export default Page;

额外说明

  • App Router的动态路由参数必须通过页面组件的params props获取,这是官方推荐的可靠方式,避免router.query的异步延迟问题。
  • 确认你的动态路由文件结构符合App Router规范:app/movie/[id]/page.js,[id]文件夹名对应路由参数名。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 18:53:20