如何在 SSR 中实现 Redux/Vuex 的状态同步?
探讨在服务端渲染(SSR)环境下,如何利用状态管理库如 Redux 或 Vuex 实现前后端状态的高效同步。文章详细介绍了从服务端初始化到客户端水合的完整流程,并对比了两者的解决方案。
使用 Redux 或 Vuex 在 SSR 中解决状态同步问题需遵循以下流程:
- 服务端状态初始化
在服务端渲染时创建新的状态管理实例并注入初始数据。
Vuex 示例:// 创建新的 Vuex store 实例 export default () => new Vuex.Store({ state, mutations, actions });
Redux 示例:
// 创建新的 Redux store export default () => createStore(reducer);
- 数据预取与填充
在服务端执行异步逻辑(如请求 API)并提交状态变更。
Vuex 方式:通过actions
异步获取数据后commit
mutation:actions: { async fetchData({ commit }) { const data = await api.get(); commit('SET_DATA', data); // 同步更新状态 } }
Redux 方式:使用中间件(如
redux-thunk
)异步调度 action:const fetchData = () => async dispatch => { const data = await api.get(); dispatch({ type: 'SET_DATA', payload: data }); };
- 状态序列化与注入 HTML
服务端将完整状态序列化后嵌入 HTML:<script> window.__INITIAL_STATE__ = ${JSON.stringify(store.getState())}; </script>
- 客户端状态水合 (Hydration)
客户端通过初始状态恢复 store,实现双向同步:
Vuex 实现:// 初始化 Vuex 时使用预填状态 new Vuex.Store({ state: window.__INITIAL_STATE__ });
Redux 实现:
// 创建 Redux store 时预加载状态 createStore(reducer, window.__INITIAL_STATE__);
- 避免客户端重复请求与水合失败
- 客户端检测机制:仅在未水合状态时执行数据请求;
- 序列化校验:避免类型丢失,如 Date 类型需特殊处理;
- 状态快照兼容性:确保服务端与客户端初始化逻辑一致,防止 hydration 错误。
方案对比:
问题点 Vuex 解决方案 Redux 解决方案 异步数据预取 Action 支持异步,同步 Commit 依赖中间件实现异步 Action 序列化风险 依赖 Proxy 无需处理序列化 JSON.stringify
需处理循环引用/类型状态脱水 通过 __INITIAL_STATE__
注入preloadedState
初始化 store