为一个大项目迁移到 redux-toolkit
Posted
技术标签:
【中文标题】为一个大项目迁移到 redux-toolkit【英文标题】:Migrate to redux-toolkit for a big project 【发布时间】:2022-01-03 09:33:57 【问题描述】:我有一个包含庞大代码库的 react 项目。我正在使用 redux、sagas 和异步减速器。 我有一个 redux-module 结构。有很多小的减速器,我将它们组合成几个大的异步减速器。 sagas 的情况也一样。
是否可以逐步迁移到redux-toolkit和rtk-query?我不能一次重写所有模块。也许有人有做同样迁移的经验?或者我应该保留我的样板代码库?)
这是异步 redux 模块之一的代码
const reducer: (state: UserState, action: UserAction) => UserState = mergeReducers(
userReducer,
settingsReducer,
signUpReducer
);
mergeReducers 函数
const mergeReducers =
(...reducers) =>
(state, action) =>
reducers.reduce((acc, reducer) => ( ...acc, ...reducer(acc, action) ), state);
所有这些减速器都是标准减速器,例如
const signUpReducer = (state: UserState = userInitialState, action: SignUpAction): UserState =>
switch (action.type)
case SIGN_UP_CONTINUE_REQUESTED:
case SIGN_UP_INITIATE_REQUESTED:
return ...state, pending: true, error: null ;
case SIGN_UP_INITIATE_SUCCEEDED:
return ...state, pending: false ;
case SIGN_UP_CONTINUE_SUCCEEDED:
return
...state,
profile: action.payload.profile,
token: action.payload.token,
error: null,
;
case SIGN_UP_INITIATE_REJECTED:
case SIGN_UP_CONTINUE_REJECTED:
return ...state, pending: false, error: action.payload ;
default:
/* ::(action.type: empty) */
return ...state ;
;
这里的模块实现
function startSaga(key, saga)
const runnableSaga = function* main()
const sagaTask = yield fork(saga);
const payload = yield take(STOP_SAGA);
if (payload === key)
yield cancel(sagaTask);
;
sagaMiddleware.run(runnableSaga);
function stopSaga(key)
store.dispatch(
payload: key,
type: STOP_SAGA,
);
export const useReduxModule = (key, reducer, saga, initialAction) =>
useEffect(() =>
if (!store.asyncReducers[key])
store.injectReducer(key, reducer);
startSaga(key, saga);
if (initialAction) initialAction();
return () =>
stopSaga(key);
store.removeReducer(key);
;
, []);
;
在反应中使用。 我需要在模块根组件中初始化redux模块
import loadSomeDateRequested, reducer, saga from './store';
const SomeComponent = ( loadData ) =>
useReduxModule(SOME_MODULE, reducer, saga, loadData);
return (
// some jsx
);
;
export default connect(null,
loadData: loadSomeDateRequested,
)(SomeComponent);
SomeComponent.propTypes =
loadData: func.isRequired,
;
存储配置
function createReducer(asyncReducers)
return combineReducers(
...staticReducers,
...asyncReducers,
);
export const sagaMiddleware = createSagaMiddleware();
const bindMiddleware = (middlewares) =>
(process.env.NODE_ENV !== 'production' && composeWithDevTools(applyMiddleware(...middlewares))) ||
applyMiddleware(...middlewares);
export default function configureStore()
const store = createStore(createReducer(), bindMiddleware([sagaMiddleware]));
store.asyncReducers = ;
store.injectReducer = (key, asyncReducer) =>
store.asyncReducers[key] = asyncReducer;
store.replaceReducer(createReducer(store.asyncReducers));
;
store.removeReducer = (key) =>
delete store.asyncReducers[key];
delete store.getState()[key];
;
return store;
export const store = configureStore();
静态减速器是
export default
[MODULE_PDF_MODAL]: pdfModalReducer,
;
我花了很多时间研究和阅读文档和示例。但是我没有找到真实项目的迁移示例,只有如何迁移最简单的 redux 存储的示例。也许有人知道如何添加一个 redux 工具包并保持现有商店的工作。因为目前,我只知道一种解决方案。而这个解决方案是一次性重写所有的redux store。 正如我在上面写的那样,我有一些异步模块,它们彼此独立。按模块迁移是现实的,但我需要在重写之前保留所有其他的工作。
非常感谢您的所有回答。希望有人可以帮助我)
解决方案
import configureStore from '@reduxjs/toolkit';
import createSagaMiddleware from 'redux-saga';
import staticReducers from '@sharedStore/staticReducers';
import combineReducers from 'redux';
function createReducer(asyncReducers)
return combineReducers(
...staticReducers,
...asyncReducers,
);
export const sagaMiddleware = createSagaMiddleware();
export default function configStore()
const store = configureStore(
reducer: createReducer(),
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(sagaMiddleware),
);
store.asyncReducers = ;
store.injectReducer = (key, asyncReducer) =>
store.asyncReducers[key] = asyncReducer;
store.replaceReducer(createReducer(store.asyncReducers));
;
store.removeReducer = (key) =>
delete store.asyncReducers[key];
delete store.getState()[key];
;
return store;
export const store = configStore();
您可以使用 redux-toolkit 并保持 redux 稳定运行。 对我来说,它是为了支持 redux 包中的 combineReducers 函数。
【问题讨论】:
【参考方案1】:Redux Toolkit 就是 Redux。由createSlice
或createReducer
创建的RTK reducer 与您亲手写的reducer 与“外部”没有什么不同。这意味着您可以对它们做任何您想做的事情,甚至可以将它们放入您的mergeReducers
。
我们的建议:将您的 createStore
切换到 configureStore
。这已经添加了一些辅助中间件,您的整个商店都将从中受益——不变性和可序列化检查等等。然后只需将您慢慢使用的减速器切换到 RTK - 只是您需要触摸的那些。随着时间的推移,您的项目将会迁移。
至于去 RTK Query - 那只是范式的改变。当然,随着时间的推移,你也可以这样做,但 reducer+saga 和 hooks+RTKQ 之间并没有太多相似之处——你必须自己决定如何处理。
【讨论】:
当然。我没有尝试在不删除用于 combineReducers 的 redux 的情况下安装工具包。以上是关于为一个大项目迁移到 redux-toolkit的主要内容,如果未能解决你的问题,请参考以下文章