NextJS中getServerSideProps无法初始化客户端状态(next-redux-wrapper等)
问题解决:Next.js + Redux-Saga 刷新页面后Redux状态丢失
问题原因
- 仅在首页的
getServerSideProps中触发了数据获取逻辑,/enquiries页面刷新时,服务端未执行数据请求,导致服务端生成的Redux状态为空,客户端hydration后状态也为空。 store/index.js中未正确导出wrapper实例,导致_app.ts中的hydration逻辑无法正常工作。- Redux Slice中的
HYDRATE处理可优化,避免潜在状态合并问题。
具体修复步骤
1. 修复Store配置,导出wrapper实例
修改store/index.js,添加createWrapper调用并导出实例:
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit' import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux' import createSagaMiddleware from "redux-saga"; import enquiryReducer from '../store/enquiry/slice'; import { createWrapper } from 'next-redux-wrapper'; import rootSaga from '../sagas/index'; const makeStore = () => { const sagaMiddleware = createSagaMiddleware(); const store = configureStore({ reducer: { enquiry: enquiryReducer, }, middleware: [...getDefaultMiddleware({ thunk: false }), sagaMiddleware], devTools: true }) //@ts-ignore store.sagaTask = sagaMiddleware.run(rootSaga); return store; } // 创建并导出wrapper实例 export const wrapper = createWrapper<AppStore>(makeStore); const store = makeStore(); export type AppStore = ReturnType<typeof makeStore>; export type RootState = ReturnType<typeof store.getState> export type AppDispatch = typeof store.dispatch export const useAppDispatch: () => AppDispatch = useDispatch
2. 为/enquiries页面添加服务端数据获取逻辑
在pages/enquiries.js中添加getServerSideProps,触发数据请求并等待Saga完成:
import { wrapper } from '../store'; import { END } from 'redux-saga'; import { startedLoadingEnquiries } from '../store/enquiry/slice'; // 其他组件导入... export const getServerSideProps = wrapper.getServerSideProps( (store) => async () => { await store.dispatch(startedLoadingEnquiries()); store.dispatch(END); await (store as any).sagaTask.toPromise(); return { props: {} }; } ); // 页面组件代码...
3. 优化Slice中的HYDRATE处理(可选但推荐)
将Slice的extraReducers改为RTK推荐的builder模式,确保状态合并正确:
import { PayloadAction, createSlice } from '@reduxjs/toolkit' import { HYDRATE } from 'next-redux-wrapper'; import { RootState } from '../index'; export enum LoadingTracker { NotStarted, Loading, Success, Failed } // 补充Enquiry类型定义 type Enquiry = { id: string; // 其他字段... }; type EnquiryState = { enquiries: Enquiry[], loadingTracker: LoadingTracker } const initialState: EnquiryState = { enquiries: [], loadingTracker: LoadingTracker.NotStarted } export const enquirySlice = createSlice({ name: 'enquiries', initialState, reducers: { loadEnquiries: (state, action: PayloadAction<Enquiry[]>) => { state.enquiries = action.payload; state.loadingTracker = LoadingTracker.Success }, failedLoadEnquiries: (state) => { state.loadingTracker = LoadingTracker.Failed; }, startedLoadingEnquiries: (state) => { state.loadingTracker = LoadingTracker.Loading; } }, extraReducers: (builder) => { builder.addCase(HYDRATE, (state, action) => { return { ...state, ...action.payload.enquiry }; }); }, }); export const { loadEnquiries, failedLoadEnquiries, startedLoadingEnquiries } = enquirySlice.actions; export default enquirySlice.reducer;
完成以上修改后,刷新/enquiries页面时,服务端会触发数据请求并将填充好的状态传递给客户端,hydration后Redux状态将保持正确,页面可正常展示列表。
内容的提问来源于stack exchange,提问作者kumuda
相关产品推荐
相关产品推荐

