使用next-redux-wrapper时,如何在非组件中调用Redux dispatch?
问题
我用next-redux-wrapper封装了React-Redux store,想在React组件外部(比如axios工具文件)调用dispatch方法,但受限于wrapper的机制无法实现。请问有没有办法在使用wrapper的同时,导入store并调用dispatch?
相关store代码:
import { combineReducers, configureStore } from '@reduxjs/toolkit'; import { persistReducer, persistStore } from 'redux-persist'; import storage from 'redux-persist/lib/storage'; import createSagaMiddleware from 'redux-saga'; import authSlice from './slices/authSlice'; import rootSaga from './sagas'; export const rootReducer = combineReducers({ [authSlice.name]: authSlice.reducer }); const sagaMiddleware = createSagaMiddleware(); const makeConfiguredStore = () => { const store = configureStore({ reducer: rootReducer, middleware: [sagaMiddleware], devTools: true, }); sagaMiddleware.run(rootSaga); return store; }; export const makeStore = () => { const persistConfig = { key: 'nextjs', whitelist: ['auth'], storage, }; const persistedReducer = persistReducer(persistConfig, rootReducer); const store: any = configureStore({ reducer: persistedReducer, middleware: [sagaMiddleware], devTools: process.env.NODE_ENV !== 'production', }); sagaMiddleware.run(rootSaga); store.__persistor = persistStore(store); // Nasty hack return store; } export const wrapper = createWrapper<AppStore>(makeStore); export type AppStore = ReturnType<typeof makeStore>; export type AppState = ReturnType<AppStore['getState']>;
我在axios工具文件中的尝试代码:
const setHeaders = async () => { const token = await refreshOrAccessToken(); if(!token){ // const store = makeStore(); 直接创建新store没用,不是应用的实例 store.dispatch(signoutUser(SESSION_EXPIRY_MSG)) msalInstance.logoutRedirect(); throw Error(SESSION_EXPIRY_MSG) } axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${token}`; };
解决方案
方法1:将客户端store实例保存为全局变量
修改makeStore函数,在创建store后仅在客户端环境将其保存为全局变量,确保组件外的代码能访问到和应用一致的store实例(避免服务器端请求间的状态污染)。
修改后的makeStore代码:
// 新增变量存储客户端store实例 let clientStore: AppStore | null = null; export const makeStore = () => { // 每次创建store时重新生成sagaMiddleware,避免重复启动saga const sagaMiddleware = createSagaMiddleware(); const persistConfig = { key: 'nextjs', whitelist: ['auth'], storage, }; const persistedReducer = persistReducer(persistConfig, rootReducer); const store: AppStore = configureStore({ reducer: persistedReducer, middleware: [sagaMiddleware], devTools: process.env.NODE_ENV !== 'production', }); sagaMiddleware.run(rootSaga); store.__persistor = persistStore(store); // 仅在客户端环境保存store实例 if (typeof window !== 'undefined') { clientStore = store; // 也可挂载到window对象,方便其他文件直接访问 (window as any).reduxStore = store; } return store; } // 导出获取客户端store的方法 export const getClientStore = () => { if (typeof window === 'undefined') { throw new Error('getClientStore只能在客户端环境调用'); } if (!clientStore) { // 若store未初始化,手动创建(应对_app.tsx之前调用的场景) clientStore = makeStore(); } return clientStore; }
在axios工具文件中使用:
import { getClientStore } from '../path/to/store'; const setHeaders = async () => { const token = await refreshOrAccessToken(); if(!token){ const store = getClientStore(); store.dispatch(signoutUser(SESSION_EXPIRY_MSG)); msalInstance.logoutRedirect(); throw Error(SESSION_EXPIRY_MSG); } axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${token}`; };
注意事项
- 禁止在服务器端代码(如
getServerSideProps、API路由)中使用这个全局store,否则会导致不同请求间的状态污染。服务器端每次请求都会调用makeStore生成新的独立store实例。 - 原代码中全局创建
sagaMiddleware会导致重复启动saga,修改后改为在makeStore内部创建实例,解决该问题。
内容的提问来源于stack exchange,提问作者Ankit Shah
相关产品推荐
相关产品推荐

