Next.js中next-redux-wrapper与Redux Toolkit、RTK Query集成及服务端数据获取问题
解决Next.js中getServerSideProps预取RTK Query数据的问题
核心问题分析
你遇到的store未定义是因为没通过next-redux-wrapper的包装器在getServerSideProps中获取服务端store实例,另外RTK Query的initiate返回Promise,必须用unwrap()等待请求完成,才能确保数据预取完毕。
步骤1:配置适配next-redux-wrapper的store
首先你的store要基于configureStore创建,导出makeStore函数供next-redux-wrapper使用,同时集成RTK Query的API切片:
// store.js import { configureStore } from '@reduxjs/toolkit' import { createWrapper } from 'next-redux-wrapper' import { listsApi } from './services/listsApi' // 你的RTK Query API切片 import useReducer from './reducers/useReducer' // 自定义reducer export const makeStore = () => { return configureStore({ reducer: { useReducer, [listsApi.reducerPath]: listsApi.reducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(listsApi.middleware), }) } export const wrapper = createWrapper(makeStore)
步骤2:修改页面的getServerSideProps
用wrapper.getServerSideProps包装你的函数,这样就能拿到服务端store实例,然后预取两个查询并等待完成:
import { wrapper } from '../store' // 导入store包装器 import { listsApi } from '../services/listsApi' // 导入API切片 const ToDoComponent = dynamic(() => import("../components/ToDoComponent"), { loading: () => <NextNProgress />, }) const ToDo = ({ darkmode }) => { const username = useSelector((state) => state.useReducer.username) const { isMobileState } = useIsMobile() // 直接用服务端预取的暗色模式数据 setNextTheme(darkmode) useRedirect() return ( <> <ToDoComponent isMobileState={isMobileState} darkmode={darkmode} /> </> ) } export const getServerSideProps = wrapper.getServerSideProps(async (context) => { const { store } = context const username = "hardcoded username" // 这里可从context.req取cookie或context.query取参数,替换硬编码值 // 预取用户暗色模式数据,等待请求完成 const darkModeResult = await store.dispatch(listsApi.endpoints.getUserDarkMode.initiate(username)).unwrap() // 预取用户列表数据,等待请求完成 await store.dispatch(listsApi.endpoints.getUserLists.initiate(username)).unwrap() // 将预取的暗色模式数据传递给组件 return { props: { darkmode: darkModeResult, }, } }) export default ToDo
步骤3:客户端组件复用预取数据
在ToDoComponent中使用RTK Query的hooks时,会自动识别服务端预取的数据,不会重复发起请求:
// ToDoComponent.js import { useGetUserListsQuery } from '../services/listsApi' const ToDoComponent = ({ isMobileState, darkmode }) => { const username = useSelector((state) => state.useReducer.username) // 直接复用服务端预取的用户列表数据 const { data: userLists } = useGetUserListsQuery(username) return ( // 组件渲染内容 ) }
关键注意事项
- 必须用
wrapper.getServerSideProps包装函数,才能获取服务端store实例 - RTK Query的
initiate返回ThunkAction,必须调用unwrap()等待请求完成,否则可能数据未加载就返回页面 - 若username不是硬编码,可从
context.req.cookies读取登录态,或从context.query获取URL参数
内容的提问来源于stack exchange,提问作者Lucas
相关产品推荐
相关产品推荐

