SSR页面嵌入组件能否做客户端数据获取?返回null问题求助
在SSR页面的嵌入组件中执行客户端数据获取的问题解决
当然可以在SSR页面的嵌入组件内执行客户端数据获取,你当前遇到返回null的问题,核心原因是路由参数获取时机错误+自定义Hook依赖缺失,以下是具体分析和修复方案:
问题根源
- 路由参数未就绪:在SSR渲染阶段,
router.query可能还未完全加载,子组件初始化时router.query.id会是undefined,导致useCollection/useDocument传入的Firestore路径无效,自然拿不到数据。 - Hook依赖缺失:
useCollection的useEffect依赖数组为空,即使后续id更新,也不会重新触发数据获取逻辑。
修复方案
方案1:直接传递Props(推荐)
父页面Solution已经通过getServerSideProps拿到了solutionId,直接将该ID通过props传给子组件,完全避开路由参数的时机问题:
修改父组件(index.js)
const Solution = ({ solution }) => { // ... 现有代码 return ( <> {/* ... 现有代码 */} <div className="grid grid-col-1 md:grid-cols-[1fr_160px] items-start gap-x-5 mt-10"> {/* 传递solution.id给子组件 */} <SolutionComments solutionId={solution.id} /> <EmojiSection solutionId={solution.id} /> </div> </> ) }
修改子组件
SolutionComments.js
const SolutionComments = ({ solutionId }) => { // 直接使用传入的solutionId,无需依赖router const { documents, isLoading, error } = useCollection(`solutions/${solutionId}/comments`) return ( <div className="mt-10 md:mt-0"> <CommentForm docID={solutionId} /> <div className="mt-10"> {isLoading && <div>加载评论中...</div>} {error && <div>{error}</div>} {documents && documents.map((comment) => ( <Comment key={comment.id} comment={comment} replies={comment.replies} /> ))} </div> </div> ) }
EmojiSection.js
const EmojiSection = ({ solutionId }) => { const { document: reactions, isLoading, error } = useDocument(`solutions/${solutionId}/reactions`, "emojis") if (isLoading) return <div>加载表情数据中...</div> if (error) return <div>{error}</div> return ( {/* 你的JSX代码 */} ) }
方案2:修复自定义Hook的依赖
不管是否传递props,都需要修复useCollection的依赖问题,确保路径变化时重新获取数据:
export const useCollection = (c) => { const [documents, setDocuments] = useState([]) const [isLoading, setIsLoading] = useState(true) const [error, setError] = useState(null) useEffect(() => { // 路径为空时直接返回,避免无效请求 if (!c) return let ref = collection(db, c) const unsubscribe = onSnapshot(ref, (snapshot) => { const results = [] snapshot.docs.forEach((doc) => { results.push({ ...doc.data(), id: doc.id }) }) setDocuments(results) setIsLoading(false) setError(null) }, (error) => { console.log(error) setError("could not fetch the data") setIsLoading(false) }) return () => unsubscribe() }, [c]) // 将路径c添加到依赖数组 return { documents, error, isLoading } }
方案3:等待路由就绪(备选)
如果必须依赖router.query,需要等待路由完全加载完成后再请求数据:
const SolutionComments = () => { const router = useRouter() const { id } = router.query // 等待路由就绪 if (!router.isReady) { return <div>加载中...</div> } const { documents, isLoading, error } = useCollection(`solutions/${id}/comments`) // ... 现有渲染逻辑 }
总结
优先选择方案1+方案2的组合,既避免了路由参数的时机问题,又保证了Hook的响应式更新,能彻底解决你当前数据返回null的问题。
内容的提问来源于stack exchange,提问作者r121
相关产品推荐
相关产品推荐

