如何在Nx Monorepo下的Next.js项目中接入Redux-Toolkit
在Nx Monorepo的Next.js项目中接入Redux Toolkit操作指南
前置准备
首先确保你的Nx工作区内已经创建好可用的Next.js应用,接下来安装必要依赖:
# npm npm install @reduxjs/toolkit react-redux next-redux-wrapper # pnpm pnpm add @reduxjs/toolkit react-redux next-redux-wrapper # yarn yarn add @reduxjs/toolkit react-redux next-redux-wrapper
注意:如果你不需要服务端渲染的状态同步,或者使用Next.js App Router模式,可以省略
next-redux-wrapper依赖。
步骤1:创建共享状态库(推荐)
Nx Monorepo下推荐将通用的Redux逻辑放到独立的共享库中,方便多应用复用,执行Nx生成命令创建库:
nx generate @nx/react:library shared/data-access --directory=shared --buildable
生成后库文件会存放在libs/shared/data-access目录下。
步骤2:编写Redux Toolkit核心逻辑
创建Slice
在共享库的src目录下新建切片文件,比如counter.slice.ts,示例逻辑如下:
import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { HYDRATE } from 'next-redux-wrapper'; interface CounterState { value: number; } const initialState: CounterState = { value: 0, }; export const counterSlice = createSlice({ name: 'counter', initialState, reducers: { increment: (state) => { state.value += 1; }, decrement: (state) => { state.value -= 1; }, incrementByAmount: (state, action: PayloadAction<number>) => { state.value += action.payload; }, }, // 适配Next.js SSR hydrate逻辑,这是和普通React项目最大的差异点 extraReducers: (builder) => { builder.addCase(HYDRATE, (state, action: any) => { return { ...state, ...action.payload.counter, }; }); }, }); export const { increment, decrement, incrementByAmount } = counterSlice.actions; export default counterSlice.reducer;
配置Store和Wrapper
在共享库src目录下新建store.ts文件,配置全局store和next-redux-wrapper的包装器:
import { configureStore } from '@reduxjs/toolkit'; import { createWrapper } from 'next-redux-wrapper'; import counterReducer from './counter.slice'; export const makeStore = () => { return configureStore({ reducer: { counter: counterReducer, // 其他reducer在此处添加 }, }); }; export type AppStore = ReturnType<typeof makeStore>; export type RootState = ReturnType<AppStore['getState']>; export type AppDispatch = AppStore['dispatch']; export const wrapper = createWrapper<AppStore>(makeStore, { debug: false });
步骤3:Next.js应用集成
Pages Router模式
修改Next.js应用的pages/_app.tsx文件,引入Provider和Wrapper:
import type { AppProps } from 'next/app'; import { Provider } from 'react-redux'; import { wrapper } from '@your-workspace/shared/data-access'; // 替换为你实际的库别名 export default function App({ Component, ...rest }: AppProps) { const { store, props } = wrapper.useWrappedStore(rest); return ( <Provider store={store}> <Component {...props.pageProps} /> </Provider> ); }
App Router模式
不需要使用next-redux-wrapper,直接在根layout中配置Provider即可,首先新建providers.tsx客户端组件:
'use client'; import { Provider } from 'react-redux'; import { makeStore } from '@your-workspace/shared/data-access'; import { ReactNode } from 'react'; export function ReduxProvider({ children }: { children: ReactNode }) { const store = makeStore(); return <Provider store={store}>{children}</Provider>; }
然后在app/layout.tsx中引入该Provider:
import { ReduxProvider } from './providers'; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="zh-CN"> <body> <ReduxProvider>{children}</ReduxProvider> </body> </html> ); }
步骤4:在组件中使用状态
配置完成后,在组件中使用Redux的方式和普通React项目完全一致,示例:
'use client'; // App Router模式下需要加该行指令 import { useSelector, useDispatch } from 'react-redux'; import { RootState, AppDispatch } from '@your-workspace/shared/data-access'; import { increment, decrement } from '@your-workspace/shared/data-access'; export default function CounterComponent() { const count = useSelector((state: RootState) => state.counter.value); const dispatch = useDispatch<AppDispatch>(); return ( <div> <button onClick={() => dispatch(decrement())}>-</button> <span>{count}</span> <button onClick={() => dispatch(increment())}>+</button> </div> ); }
注意事项
- Nx工作区默认会在
tsconfig.base.json中自动为新建的库配置路径别名,你可以直接使用别名导入库内容,不需要编写冗长的相对路径 - 如果你的项目不需要服务端渲染的状态同步,可以直接跳过next-redux-wrapper的配置,仅在客户端侧初始化store即可,逻辑和普通React项目完全一致
- 原Nx官方React Redux指引不适配Next.js的核心原因是没有考虑Next.js的SSR/SSG场景下的状态hydration需求,按照上述步骤增加对应处理即可正常使用
内容的提问来源于stack exchange,提问作者John John
相关产品推荐
相关产品推荐

