如何在Next.js v13 App目录中使用服务端Redux?含报错解决与示例
在Next.js 13 App目录中使用Redux的完整方案
1. 能否替代Next.js Redux Wrapper使用Redux?
完全可以。Next.js 13 App Router的组件模型(服务端/客户端组件分离)和Pages Router不同,不需要依赖next-redux-wrapper,直接结合Redux Toolkit与React的Provider就能实现状态管理,同时支持服务端状态初始化。
2. 如何创建服务端状态?
在App Router中,你可以在服务端组件中获取初始数据(比如从API、数据库拉取),将其作为预加载状态传递给Redux store,再通过客户端组件的Provider包裹子组件,让客户端组件访问到初始化后的状态。
3. React createContext错误的解决方法
这个错误几乎都是因为在服务端组件中使用了客户端专属API(比如createContext、Redux的Provider或useSelector/useDispatch hooks)。App Router规定服务端组件不能调用客户端API,解决步骤:
- 所有涉及Redux
Provider、使用Redux hooks的组件,必须在文件顶部添加'use client'指令,标记为客户端组件 - 服务端组件仅负责获取初始数据,不参与状态管理的逻辑实现
4. 可运行的示例代码
第一步:创建Redux Store(store.ts)
import { configureStore, createSlice } from '@reduxjs/toolkit'; interface CounterState { value: number; } const initialState: CounterState = { value: 0, }; const counterSlice = createSlice({ name: 'counter', initialState, reducers: { increment: (state) => { state.value += 1; }, decrement: (state) => { state.value -= 1; }, }, }); export const { increment, decrement } = counterSlice.actions; export const makeStore = (preloadedState?: Partial<CounterState>) => { return configureStore({ reducer: { counter: counterSlice.reducer }, preloadedState, }); }; export type AppStore = ReturnType<typeof makeStore>; export type RootState = ReturnType<AppStore['getState']>; export type AppDispatch = AppStore['dispatch'];
第二步:创建Redux Provider组件(Providers.tsx)
'use client'; import { useRef } from 'react'; import { Provider } from 'react-redux'; import { makeStore, AppStore } from './store'; export default function Providers({ children, initialState, }: { children: React.ReactNode; initialState?: Parameters<typeof makeStore>[0]; }) { const storeRef = useRef<AppStore>(); if (!storeRef.current) { storeRef.current = makeStore(initialState); } return <Provider store={storeRef.current}>{children}</Provider>; }
第三步:服务端组件注入初始状态(app/page.tsx)
import Providers from './Providers'; import Counter from './Counter'; // 模拟服务端获取初始数据 async function getInitialCounterValue() { await new Promise(resolve => setTimeout(resolve, 100)); return { value: 5 }; } export default async function Home() { const initialState = await getInitialCounterValue(); return ( <Providers initialState={{ counter: initialState }}> <main> <h1>Next.js 13 App Router + Redux</h1> <Counter /> </main> </Providers> ); }
第四步:使用Redux的客户端组件(Counter.tsx)
'use client'; import { useSelector, useDispatch } from 'react-redux'; import { increment, decrement } from './store'; import type { RootState } from './store'; export default function Counter() { const count = useSelector((state: RootState) => state.counter.value); const dispatch = useDispatch(); return ( <div> <p>Count: {count}</p> <button onClick={() => dispatch(increment())}>Increment</button> <button onClick={() => dispatch(decrement())}>Decrement</button> </div> ); }
以上代码可直接在在线编辑器中运行,只需安装依赖(@reduxjs/toolkit react-redux next react react-dom)即可。
内容的提问来源于stack exchange,提问作者girish chaudhari
相关产品推荐
相关产品推荐

