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

NextJS结合React Context使用时页面源码无预渲染HTML的问题排查

Next.js 预渲染失效问题:Context 与 Redux-Persist 导致无预渲染 HTML

问题场景

在 Next.js 中使用 React Context(InternetConnectionStatusProvider)和 Redux-Persist 时,页面源码中看不到完整的预渲染 HTML,特定标签后无预渲染数据。当前 _app.js 的组件嵌套结构如下:

<Provider store={store}>
  <PersistGate persistor={persistor}>
    <InternetConnectionStatusProvider>
      <Component {...pageProps} />
    {/* </InternetConnectionStatusProvider> */}
  </PersistGate>
</Provider>

InternetConnectionStatusContext 代码:

const { createContext, useState, useEffect, useMemo } = require('react')

export const InternetConnectionStatusContext = createContext({
  isOnline: true,
})

export const InternetConnectionStatusProvider = ({ children }) => {
  const [isOnline, setOnline] = useState(true)

  // if (typeof navigator === 'undefined') {
  //   return null
  // }

  useEffect(() => {
    setOnline(navigator.onLine)

    window.addEventListener('online', () => {
      setOnline(true)
    })

    window.addEventListener('offline', () => {
      setOnline(false)
    })

    return () => {
      window.removeEventListener('online', () => {
        setOnline(true)
      })

      window.removeEventListener('offline', () => {
        setOnline(false)
      })
    }
  }, [navigator.onLine])

  const value = useMemo(() => ({ isOnline }))

  return (
    <InternetConnectionStatusContext.Provider value={value}>
      {children}
    </InternetConnectionStatusContext.Provider>
  )
}

问题根源

  1. Context 端问题:Next.js 预渲染(SSG/SSR)在服务端执行,服务端不存在 navigator、window 等浏览器专属 API。你的 Provider 中直接在 useEffect 依赖里使用 navigator.onLine,服务端渲染时会触发状态异常;如果启用注释掉的判断,会直接返回 null,完全阻断子组件预渲染。
  2. Redux-Persist 端问题:PersistGate 默认会等待 localStorage 加载完成后才渲染子组件,但服务端没有 localStorage,会一直处于加载等待状态,导致服务端无法生成子组件的预渲染 HTML。

解决方案

一、修复 InternetConnectionStatusProvider

修改 Provider,仅在客户端执行浏览器相关逻辑,服务端直接用初始状态渲染子组件:

const { createContext, useState, useEffect, useMemo } = require('react')

export const InternetConnectionStatusContext = createContext({
  isOnline: true,
})

export const InternetConnectionStatusProvider = ({ children }) => {
  const [isOnline, setOnline] = useState(true)

  useEffect(() => {
    // 仅在客户端挂载时执行
    const handleOnline = () => setOnline(true)
    const handleOffline = () => setOnline(false)

    // 初始化网络状态
    setOnline(navigator.onLine)
    // 添加监听事件
    window.addEventListener('online', handleOnline)
    window.addEventListener('offline', handleOffline)

    // 组件卸载时清理监听
    return () => {
      window.removeEventListener('online', handleOnline)
      window.removeEventListener('offline', handleOffline)
    }
  }, []) // 空依赖确保仅客户端挂载执行一次

  const value = useMemo(() => ({ isOnline }), [isOnline]) // 依赖isOnline避免无效更新

  return (
    <InternetConnectionStatusContext.Provider value={value}>
      {children}
    </InternetConnectionStatusContext.Provider>
  )
}

二、修复 Redux-Persist 预渲染问题

修改 _app.js,区分服务端和客户端渲染逻辑,服务端直接渲染子组件,客户端再加载持久化数据:

import { useEffect, useState } from 'react'
import { Provider } from 'react-redux'
import { PersistGate } from 'redux-persist/integration/react'
import { store, persistor } from '../store'
import { InternetConnectionStatusProvider } from '../context/InternetConnectionStatus'

function MyApp({ Component, pageProps }) {
  const [isClient, setIsClient] = useState(false)

  useEffect(() => {
    setIsClient(true)
  }, [])

  // 服务端渲染:直接渲染,不等待持久化加载
  if (!isClient) {
    return (
      <Provider store={store}>
        <InternetConnectionStatusProvider>
          <Component {...pageProps} />
        </InternetConnectionStatusProvider>
      </Provider>
    )
  }

  // 客户端渲染:加载持久化数据后渲染
  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <InternetConnectionStatusProvider>
          <Component {...pageProps} />
        </InternetConnectionStatusProvider>
      </PersistGate>
    </Provider>
  )
}

export default MyApp

三、验证效果

运行 next build && next export(SSG)或启动服务访问 SSR 页面,查看页面源码,确认子组件的 HTML 已正常预渲染。

内容的提问来源于stack exchange,提问作者Mic Scofield

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 12:10:22