Next.js刷新Firebase动态路由页报indexOf属性访问n未定义错误
错误原因
这个报错有两个核心诱因:
- Next.js 动态路由的
router.query参数是客户端hydrate完成后才异步填充的:硬刷新页面时,组件初次挂载触发useEffect的节点,id还是undefined,你把undefined传入Firebase的doc()方法作为文档ID参数,Firestore内部校验路径时会对参数调用indexOf()方法,对undefined调用该方法就抛出了你看到的类型错误。 - 客户端点击跳转时功能正常,是因为路由跳转在Next.js客户端运行时内完成,跳转前已经解析好了路由参数,组件挂载时
id已经是有效值,不会触发异常。
另外你的代码还存在三个隐性问题:
useEffect依赖数组为空,就算后续id解析完成,也不会重新触发数据订阅,极端场景下会拿不到数据- 没有调用
onSnapshot返回的取消订阅方法,组件卸载时会造成内存泄漏 getFirestore()未传入已初始化的Firebase App实例,部分场景下会因为db实例未就绪触发异常
修复方案
按以下步骤修改代码即可:
- 第一步:修正Firebase初始化逻辑,确保db实例绑定到已初始化的App上
fbconfig.js修正后示例:
import { initializeApp } from "firebase/app"; import { getFirestore } from "firebase/firestore"; // 替换为你自己的Firebase项目配置 const firebaseConfig = { apiKey: "你的配置", authDomain: "你的配置", projectId: "你的配置", storageBucket: "你的配置", messagingSenderId: "你的配置", appId: "你的配置" }; const app = initializeApp(firebaseConfig); // 传入初始化完成的app实例获取db export const db = getFirestore(app);
- 第二步:给动态路由页的
useEffect增加参数守卫、补全依赖、添加卸载清理逻辑[id].js中useEffect部分修正后代码:
useEffect(() => { // id未解析完成时直接返回,不执行Firestore调用 if (!id) return; const docRef = doc(db, 'posts', id); // 保存取消订阅的方法 const unsubscribe = onSnapshot(docRef, (snapshot) => { // 增加文档存在性判断,避免读取不存在的文档时报错 if (snapshot.exists()) { setPost(snapshot.data()); } }); // 组件卸载时取消实时订阅,防止内存泄漏 return () => unsubscribe(); }, [id]); // 将id加入依赖数组,id变化时重新执行订阅逻辑
- 第三步(可选优化):修正路由跳转写法,避免嵌套路由场景下跳转异常
把点击事件里的router.push(post.id)改为router.push(/${post.id}),使用绝对路径跳转。
内容的提问来源于stack exchange,提问作者Jaydendev
相关产品推荐
相关产品推荐

