NextJS中getServerSideProps传递Props渲染Firebase推文失败
我正在用NextJS结合Firebase开发推特克隆训练项目,尝试通过getServerSideProps函数从Firebase数据库获取推文并传递给Home页面组件。控制台能打印出正确的推文数组,但页面无法渲染这些推文;而使用useEffect进行客户端fetch API请求的方式却能正常显示推文。需要排查getServerSideProps传递Props失败的问题。
相关代码
Home.jsx组件
import { useContext, useEffect} from 'react'; import { getTweets } from '@/firebase/getTweets'; import { useRouter } from 'next/router'; import { AuthContext } from '@/contexts/AuthContext'; import Image from 'next/image'; import Sidebar from "@/components/Sidebar" import TweetForm from '@/components/TweetForm'; import Searchbar from '@/components/Searchbar'; import Tweet from '@/components/Tweet'; import logo from "/public/logo.png"; import Recommendation from '@/components/Recommendation'; export default function Home({ tweets }) { const { currentUser } = useContext(AuthContext); const router = useRouter(); useEffect(() => { if(!currentUser) { router.push('/'); } },[currentUser,router]); return ( <div className="flex border-black h-screen xs:flex-col-reverse sm:flex-row md:w-[80%] lg:w-[80%] md:mx-auto lg:mx-auto"> <Sidebar/> <div className="p-3 xs:h-[90%] xs:relative xs:overflow-auto xs:w-full sm:h-full xl:w-[40%] 2xl:w-[60%]"> <TweetForm currentUser={currentUser}/> <div > { tweets && tweets.map((tweet) => ( <Tweet key={tweet.id} username={tweet.username} tweetContent={tweet.content} profile={tweet.profileImage} /> ) ) } </div> </div> <div className="border w-[35%] xs:hidden sm:hidden lg:hidden xl:block"> <div className="searchbar"> <Searchbar/> <div className="p-4 w-[90%] mx-auto rounded-lg bg-gray-300"> <Recommendation/> <Recommendation/> <Recommendation/> <Recommendation/> <Recommendation/> </div> </div> </div> <div className="w-full sm:hidden"> <Image src={logo} alt="Twitter logo" width={75} height={75} className='xs:mx-auto' /> </div> </div> ) } export async function getServerSideProps() { const tweets = await getTweets(); console.log('tweets in getServerSideProps() :', tweets) return { props: { tweets, } } }
getTweets.js
import { collection, getDocs, orderBy, query } from "firebase/firestore"; import { db } from "./config"; export const getTweets = async () => { try { const tweetsRef = collection(db, "tweets"); const q = query(tweetsRef, orderBy("createdAt", "desc")); const querySnapshot = await getDocs(q); const tweets = querySnapshot.docs.map((doc) => { return { id: doc.id, ...doc.data() }; }); return tweets; } catch (error) { console.error("Error getting tweets:", error); return []; } };
可正常工作的客户端请求方式
useEffect(() => { async function fetchTweets() { const res = await fetch("http://localhost:3000/api/getTweetAPI"); const data = await res.json(); setTweets(data); } fetchTweets(); }, []);
排查解决方案
1. 修复Firebase数据序列化问题
NextJS的getServerSideProps返回的Props必须是可JSON序列化的数据,而Firebase的doc.data()可能包含Timestamp这类无法直接序列化的对象。客户端API请求能正常工作,是因为API路由返回数据时自动将Timestamp转为了字符串,但getServerSideProps直接传递原始数据会导致序列化失败,最终组件无法收到正确的Props。
修改getTweets.js中的数据处理逻辑,将Timestamp转为可序列化的字符串:
export const getTweets = async () => { try { const tweetsRef = collection(db, "tweets"); const q = query(tweetsRef, orderBy("createdAt", "desc")); const querySnapshot = await getDocs(q); const tweets = querySnapshot.docs.map((doc) => { const tweetData = doc.data(); // 将Firebase Timestamp转为ISO字符串 return { id: doc.id, ...tweetData, createdAt: tweetData.createdAt?.toISOString() || new Date().toISOString() }; }); return tweets; } catch (error) { console.error("Error getting tweets:", error); return []; } };
2. 验证组件实际接收的Props
在Home组件内添加日志,确认是否真的收到了tweets数据:
export default function Home({ tweets }) { // 新增日志,查看组件实际接收的props console.log('tweets received in Home component:', tweets); const { currentUser } = useContext(AuthContext); const router = useRouter(); // ... 其余代码不变 }
如果日志显示tweets为undefined或空数组,说明序列化问题未解决;如果显示正确数组但不渲染,检查Tweet组件的Props映射是否正确(比如确认tweet.content字段是否存在,有没有拼写错误)。
3. 确认Firebase服务端初始化正确性
客户端的Firebase配置在服务端环境中可能无法正常工作,需要确保db实例在服务端能正确初始化。如果你的Firebase配置仅针对客户端,需要为服务端单独配置Admin SDK,或者确保服务端能访问到正确的Firebase环境变量。
4. 确认路由模式兼容性
如果使用的是NextJS 13+的App Router,getServerSideProps仅在Pages Router下生效。确认你的Home.jsx位于pages目录下,而非app目录。
内容的提问来源于stack exchange,提问作者fares.dev

