从 redux 迁移到 redux-toolkit 使反应应用程序显着变慢
Migration from redux to redux-toolkit made react app significantly slow
我有这个 React 应用程序,我以前用旧的方式编写 redux 代码,我使用了 redux 和 redux-thunk,但是,将这个包更新到更新的版本,我在我使用的函数的地方有这个警告在应用程序中创建我的商店刚刚被弃用,他们建议迁移到 RTK。
但是,在将所有主要内容更改为这种编写 redux 的新方式后,一切都变慢了,多个操作需要更多时间才能完成,这影响了 UI,让人感觉不舒服。
所以,我想向您展示我编写操作的方式、我的 reducer、我如何更新数据以及我几乎是如何完成所有操作的。
这是store/config
import { configureStore } from '@reduxjs/toolkit';
import { useDispatch } from 'react-redux';
import reducers from './reducers';
export const storeConfig = configureStore({
reducer: reducers,
devTools: true,
});
// Types for dispatching actions and store's data itself
type AppDispatch = typeof storeConfig.dispatch;
export type reducersType = ReturnType<typeof reducers>;
// Types for custom useDispatch
export const useTypedDispatch = () => useDispatch<AppDispatch>();
这些是我的减速器
import { combineReducers } from '@reduxjs/toolkit';
import layout from './layoutReducer';
import pickupsNoAssign from './pickupsNoAssignReducer';
const reducers = combineReducers({ layout, pickupsNoAssign });
export default reducers;
这是我的 layout reducer 和他的动作
export interface ILayoutInitialState {
authentication?: IAuthentication;
authorizations?: IAuthorizations;
applicationOption?: IAppOptionsPayload;
isLeftDrawerOpen: boolean;
terminalSeleccionada?: string | number;
terminalNumber?: number;
serverError: string;
}
const initialState: ILayoutInitialState = {
isLeftDrawerOpen: true,
serverError: '',
};
const layoutReducer = createSlice({
name: layout,
initialState,
reducers: {
selectedTerminal: (state, { payload: { id, terminal } }: PayloadAction<ISelectedTerminalPayload>) => {
state.terminalSeleccionada = terminal;
state.terminalNumber = id;
},
selectedAppOption: (state, { payload }: PayloadAction<IAppOptionsPayload>) => {
state.applicationOption = payload;
},
leftDrawerAction: (state) => {
return {
...state,
isLeftDrawerOpen: !state.isLeftDrawerOpen,
};
},
},
extraReducers: (builder) => {
// authenticating
builder.addCase(authenticating.fulfilled, (state, { payload }) => {
const isThereToken = localStorage.getItem('accessToken');
if (!isThereToken) {
localStorage.setItem('accessToken', JSON.stringify({ ...payload.token }));
}
state.authentication = payload?.token;
state.authorizations = payload.data;
state.applicationOption = payload.appSelected;
state.terminalSeleccionada = `${payload?.token.terminal}-${payload?.token.abreviado}`;
state.terminalNumber = payload?.token.terminal;
});
builder.addCase(authenticating.rejected, (state, { payload }) => {
state.serverError = payload?.errorMessage!;
});
},
});
export const { selectedTerminal, selectedAppOption, leftDrawerAction } = layoutReducer.actions;
export default layoutReducer.reducer;
import { createAsyncThunk } from '@reduxjs/toolkit';
import {
ITerminales,
IAuthenthicatingParameters,
IAuthenthicatingPayload,
} from '../../domain/entities/redux/interfaceLayout';
import { layout } from '../../domain/helpers/types';
import { gettingPermission } from '../../infrastructure/services/api/layout/appPermissions';
// Validating authorizations
export const authenticating = createAsyncThunk<
IAuthenthicatingPayload,
IAuthenthicatingParameters,
{
rejectValue: { errorMessage: string };
}
>(`${layout}/authenticating`, async ({ token, navigate, goTo }, { rejectWithValue }) => {
try {
const data = await gettingPermission(token);
if (data && data.isError !== true && data.response !== null) {
// Selecting default app option
const optionTitle = data.response[0].permisos.aplicaciones.find(
(single) => single.id === 'sigo-distribucion',
)?.menus[0].nombre;
const optionApp = data.response[0].permisos.aplicaciones.find((single) => single.id === 'sigo-distribucion')
? data.response[0].permisos.aplicaciones.find((single) => single.id === 'sigo-distribucion')!.menus[0]
.sub_menu![0].nombre
: undefined;
// Adding default terminal
const addDefaultTerminal: ITerminales = { id: token.terminal, abreviatura: token.abreviado };
data.response[0].terminales.push(addDefaultTerminal);
navigate(goTo);
return { token, data, appSelected: { optionTitle, optionApp } };
}
} catch (err) {
console.log(err);
}
return rejectWithValue({ errorMessage: 'Hubo un fallo al obtener los permisos' });
});
我几乎在保存用户数据,并在 UI 中操作一些选项。
我是否用不良做法更新了状态?我的 actions/api 调用(使用 createAsyncThunk)写错了吗?
是什么导致了这种行为?
如前所述,RTK 实际上添加了不变性和可序列化检查:
https://redux-toolkit.js.org/api/getDefaultMiddleware
这很可能是延迟的根本原因,我有不变性检查的经验,验证一些非常大的商店可能需要几十秒。
RTK 声称在生产模式下未启用检查,但是,如果您想完全禁用它们,请执行以下操作(从上面截取的代码 link + 一些小修改):
const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
thunk: true,
serializableCheck: false,
immutableCheck: false,
}),
})
我有这个 React 应用程序,我以前用旧的方式编写 redux 代码,我使用了 redux 和 redux-thunk,但是,将这个包更新到更新的版本,我在我使用的函数的地方有这个警告在应用程序中创建我的商店刚刚被弃用,他们建议迁移到 RTK。
但是,在将所有主要内容更改为这种编写 redux 的新方式后,一切都变慢了,多个操作需要更多时间才能完成,这影响了 UI,让人感觉不舒服。
所以,我想向您展示我编写操作的方式、我的 reducer、我如何更新数据以及我几乎是如何完成所有操作的。
这是store/config
import { configureStore } from '@reduxjs/toolkit';
import { useDispatch } from 'react-redux';
import reducers from './reducers';
export const storeConfig = configureStore({
reducer: reducers,
devTools: true,
});
// Types for dispatching actions and store's data itself
type AppDispatch = typeof storeConfig.dispatch;
export type reducersType = ReturnType<typeof reducers>;
// Types for custom useDispatch
export const useTypedDispatch = () => useDispatch<AppDispatch>();
这些是我的减速器
import { combineReducers } from '@reduxjs/toolkit';
import layout from './layoutReducer';
import pickupsNoAssign from './pickupsNoAssignReducer';
const reducers = combineReducers({ layout, pickupsNoAssign });
export default reducers;
这是我的 layout reducer 和他的动作
export interface ILayoutInitialState {
authentication?: IAuthentication;
authorizations?: IAuthorizations;
applicationOption?: IAppOptionsPayload;
isLeftDrawerOpen: boolean;
terminalSeleccionada?: string | number;
terminalNumber?: number;
serverError: string;
}
const initialState: ILayoutInitialState = {
isLeftDrawerOpen: true,
serverError: '',
};
const layoutReducer = createSlice({
name: layout,
initialState,
reducers: {
selectedTerminal: (state, { payload: { id, terminal } }: PayloadAction<ISelectedTerminalPayload>) => {
state.terminalSeleccionada = terminal;
state.terminalNumber = id;
},
selectedAppOption: (state, { payload }: PayloadAction<IAppOptionsPayload>) => {
state.applicationOption = payload;
},
leftDrawerAction: (state) => {
return {
...state,
isLeftDrawerOpen: !state.isLeftDrawerOpen,
};
},
},
extraReducers: (builder) => {
// authenticating
builder.addCase(authenticating.fulfilled, (state, { payload }) => {
const isThereToken = localStorage.getItem('accessToken');
if (!isThereToken) {
localStorage.setItem('accessToken', JSON.stringify({ ...payload.token }));
}
state.authentication = payload?.token;
state.authorizations = payload.data;
state.applicationOption = payload.appSelected;
state.terminalSeleccionada = `${payload?.token.terminal}-${payload?.token.abreviado}`;
state.terminalNumber = payload?.token.terminal;
});
builder.addCase(authenticating.rejected, (state, { payload }) => {
state.serverError = payload?.errorMessage!;
});
},
});
export const { selectedTerminal, selectedAppOption, leftDrawerAction } = layoutReducer.actions;
export default layoutReducer.reducer;
import { createAsyncThunk } from '@reduxjs/toolkit';
import {
ITerminales,
IAuthenthicatingParameters,
IAuthenthicatingPayload,
} from '../../domain/entities/redux/interfaceLayout';
import { layout } from '../../domain/helpers/types';
import { gettingPermission } from '../../infrastructure/services/api/layout/appPermissions';
// Validating authorizations
export const authenticating = createAsyncThunk<
IAuthenthicatingPayload,
IAuthenthicatingParameters,
{
rejectValue: { errorMessage: string };
}
>(`${layout}/authenticating`, async ({ token, navigate, goTo }, { rejectWithValue }) => {
try {
const data = await gettingPermission(token);
if (data && data.isError !== true && data.response !== null) {
// Selecting default app option
const optionTitle = data.response[0].permisos.aplicaciones.find(
(single) => single.id === 'sigo-distribucion',
)?.menus[0].nombre;
const optionApp = data.response[0].permisos.aplicaciones.find((single) => single.id === 'sigo-distribucion')
? data.response[0].permisos.aplicaciones.find((single) => single.id === 'sigo-distribucion')!.menus[0]
.sub_menu![0].nombre
: undefined;
// Adding default terminal
const addDefaultTerminal: ITerminales = { id: token.terminal, abreviatura: token.abreviado };
data.response[0].terminales.push(addDefaultTerminal);
navigate(goTo);
return { token, data, appSelected: { optionTitle, optionApp } };
}
} catch (err) {
console.log(err);
}
return rejectWithValue({ errorMessage: 'Hubo un fallo al obtener los permisos' });
});
我几乎在保存用户数据,并在 UI 中操作一些选项。
我是否用不良做法更新了状态?我的 actions/api 调用(使用 createAsyncThunk)写错了吗?
是什么导致了这种行为?
如前所述,RTK 实际上添加了不变性和可序列化检查: https://redux-toolkit.js.org/api/getDefaultMiddleware
这很可能是延迟的根本原因,我有不变性检查的经验,验证一些非常大的商店可能需要几十秒。
RTK 声称在生产模式下未启用检查,但是,如果您想完全禁用它们,请执行以下操作(从上面截取的代码 link + 一些小修改):
const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
thunk: true,
serializableCheck: false,
immutableCheck: false,
}),
})