@relotus/store
Библиотека для управления стейтом приложения и работы с ним.
Мотивация
В проектах React UI Team в качестве стейт-менеджера используется Redux. Для уменьшения boilerplate-кода и облегчения работы со стейтом используется пакет @reduxjs/toolkit
.
Тем не менее в проектах по прежнему имеется большой кусок повторяющегося кода: инициализация стора и утилитарный код. Помимо этого в команде было найдено несколько интересных решений, которые тоже хотелось бы использовать во всех проектах.
Использование
Для использования библиотеки предварительно необходимо описать стейт приложения:
interface SomeSliceState {
}
interface OtherSliceState {
}
import { SomeSliceState } from 'modules/SomeModule';
import { OtherSliceState } from 'modules/OtherModule';
export interface RootState {
someSlice: SomeSliceState;
otherSlice: OtherSliceState;
}
Этот тип (RootState
) будет использоваться в качестве типа для типизации стора.
configureStore
Это обертка над configureStore
из redux-toolkit.
Функция принимает в качестве аргументов тот же набор параметров, за двумя исключениями:
- вместо
reducer
(одного корневого редьюсера) можно использовать reducers
- объект из редьюсров, на основе которого будет создан корневой редюсер - вместо
middleware
необходимо передавать middlewares
- Middleware[]
Пример использования
import { configureStore } from '@relotus/store';
import { someSlice } from 'modules/SomeModule';
import { RootState } from '../types';
export const store = configureStore<RootState>({
reducers: { [someSlice.name]: someSlice.reducer },
devTools: process.env.NODE_ENV !== 'production',
});
getSliceCreator
Эта функция обертка над createSlice которая добавляет строгой типизации и расширяет функционал.
Пример использования
Для использования типизированного createSlice
:
export const createSlice = getSliceCreator<RootState>();
Далее в слайсе модуля:
import { createSlice } from '../../../services';
import { RootState } from '../../../types';
export type SliceState = RootState['someSlice'];
export const initialState: SliceState = {
title: undefined,
};
const uiSlice = createSlice({
name: 'someSlice',
initialState,
reducers: {
setTitle(state, { payload }: PayloadAction<string | undefined>) {
state.title = payload;
},
},
});
export const {
reducer,
name,
actions,
useSomeSliceDispatch,
selectDomain,
} = uiSlice;
useDispatchActions
Этот хук - обертка над bindActionCreators.
Пример использования
В большинстве случаев для того чтобы использовать экшены из слайса их нужно диспатчить
const dispatch = useDispatch();
const handleAction = useCallback(() => dispatch(someSlice.actions.someAction));
return <button onClick={handleAction}>Test</button>;
С использованием хука useDispatchActions
этот код становится более чистым:
const { someAction } = useDispatchActions(someSlice.actions));
return <button onClick={someAction}>Test</button>;
❗ если слайс создан через getSliceCreator (например с именем user
), то у него есть хук useUserDispatch