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

SSR页面嵌入组件能否做客户端数据获取?返回null问题求助

在SSR页面的嵌入组件中执行客户端数据获取的问题解决

当然可以在SSR页面的嵌入组件内执行客户端数据获取,你当前遇到返回null的问题,核心原因是路由参数获取时机错误+自定义Hook依赖缺失,以下是具体分析和修复方案:

问题根源

  1. 路由参数未就绪:在SSR渲染阶段,router.query可能还未完全加载,子组件初始化时router.query.id会是undefined,导致useCollection/useDocument传入的Firestore路径无效,自然拿不到数据。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 13:31:01