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

SSR场景下如何延迟Redux Store初始化至客户端Hydration完成后?

解决SSR/SSG下Redux持久化导致的Hydration错误(延迟加载客户端状态)

核心思路:先使用服务端注入的初始状态完成Hydration,保证客户端初始UI与服务端完全匹配,待Hydration完成后再延迟加载localStorage中的状态并更新Store。

1. 修改客户端入口文件(_default.page.client.tsx)

import { hydrateRoot } from 'react-dom/client'
import { Provider } from 'react-redux'
import { createStore } from './store'
import { loadState, saveState } from './localStorage'
import App from './App'

// 1. 优先使用服务端传递的初始状态,确保与服务端渲染UI一致
const serverInitialState = window.__INITIAL_STATE__ // vite-plugin-ssr会自动注入该全局变量
const store = createStore(serverInitialState)

// 保持状态订阅保存逻辑不变
store.subscribe(() => {
  saveState(store.getState())
})

// 2. 执行Hydration,并等待完成后延迟恢复本地状态
const root = hydrateRoot(
  document.getElementById('root')!,
  <Provider store={store}>
    <App />
  </Provider>
)

// Hydration完成后触发状态恢复
root.then(() => {
  setTimeout(() => {
    const localSavedState = loadState()
    if (localSavedState) {
      // 方式1:通过自定义action合并本地状态(更可控)
      store.dispatch({
        type: 'LOCAL_STATE_RESTORE',
        payload: localSavedState
      })
      // 方式2:Redux-Toolkit可调用对应slice的恢复action
      // store.dispatch(userSlice.actions.restoreUser(localSavedState.user))
    }
  }, 500) // 延迟0.5秒执行
})

2. 在Redux Store中处理状态恢复逻辑

如果使用Redux-Toolkit,以用户模块为例,在slice中添加恢复状态的action:

// store/slices/userSlice.ts
import { createSlice } from '@reduxjs/toolkit'

const userSlice = createSlice({
  name: 'user',
  initialState: { code: '' },
  reducers: {
    restoreUser: (state, action) => {
      // 合并本地状态,避免覆盖服务端预取数据
      return { ...state, ...action.payload }
    }
  }
})

export const { restoreUser } = userSlice.actions
export default userSlice.reducer

如果是传统Redux,在reducer中添加对应case:

// store/reducers/index.ts
const rootReducer = (state, action) => {
  switch (action.type) {
    case 'LOCAL_STATE_RESTORE':
      // 仅更新需要持久化的字段
      return {
        ...state,
        user: { ...state.user, ...action.payload.user }
      }
    default:
      return state
  }
}

3. 确保服务端正确传递初始状态

在服务端渲染入口(如pages/index/index.page.server.tsx)中,将Store状态注入页面上下文:

import { renderToString } from 'react-dom/server'
import { Provider } from 'react-redux'
import { createStore } from '../../store'
import App from '../../App'

export async function render() {
  const store = createStore()
  // 服务端预取数据(如有需要)
  // await store.dispatch(fetchInitialCode())

  const html = renderToString(
    <Provider store={store}>
      <App />
    </Provider>
  )

  return {
    html,
    pageContext: {
      initialState: store.getState() // vite-plugin-ssr自动挂载到window.__INITIAL_STATE__
    }
  }
}

关键说明

  • 先使用服务端状态完成Hydration,彻底避免客户端初始UI与服务端不匹配的问题
  • 延迟恢复本地状态的时机是Hydration完成后,此时DOM已稳定,更新状态只会触发客户端渲染,不会触发Hydration校验
  • 建议合并状态而非直接替换整个Store,避免覆盖服务端预取的有效数据

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 21:47:33