Centralize your Redux application logic in one place.
redux-rtk-effects enables developers to centralize their Redux application logic inside the reducer. It does so, providing a fully typed reducer API that allows to define action handlers with associated effects.
reducer: {
onModuleInit: {
handler: (state) => {
state.isLoading = true;
},
effect: async (_, { dispatch, extra }) => {
const user = await extra.environment.userRepository.getUser();
dispatch(extra.actions.handleUserResponse(user));
},
},
handleUserResponse: (state, { payload }) => {
state.user = payload;
state.isLoading = false;
},
}
You can install the package with npm:
npm install redux-rtk-effects
or yarn:
yarn add redux-rtk-effects
To use redux-rtk-effects in your application, follow the example below:
import { createAction } from '@reduxjs/toolkit';
import { createStoreFactory, createEnvironment } from 'redux-rtk-effects';
// Define dependencies needed inside side-effects.
interface Environment {
userRepository: {
getUser: () => Promise<{
name: string;
}>;
};
}
// Create store factory using createStoreFactory API
const { factory } = createStoreFactory({
initialState: { user: null as null | User, isLoading: false },
actions: {
onModuleInit: createAction('onModuleInit'),
handleUserResponse: createAction<User>('handleUserResponse'),
},
environment: createEnvironment<Environment>(),
reducer: {
// You can define action handlers as simple functions
handleUserResponse: (state, { payload }) => {
state.user = payload;
state.isLoading = false;
},
// Or, you can definec action handlers with associated effects
onModuleInit: {
handler: (state) => {
state.isLoading = true;
},
// Effect that will be triggered once
// the onModuleInit action is dispatched
effect: async (_, { dispatch, extra }) => {
const user = await extra.environment.userRepository.getUser();
dispatch(extra.actions.handleUserResponse(user));
},
},
},
});
// Create the store using the factory function and inject in the environment
const environment: Environment = {
userRepository: {
getUser: () => Promise.resolve({ name: 'John Doe' }),
},
};
// Here you have your RTK store! With effects configuration setup.
const store = factory(environment);
Looking at the most used alternatives, they all handle side effects inside middlewares, scattering application logic between those and the reducer.
Taking inspiration from the Elm architecture and Swift Composable Architecture, redux-rtk-effects aims to centralize application logic inside the reducer, providing a fully typed API to define action handlers with associated effects.
At the same time, the Redux ecosystem is evolving toward the usage of Redux Toolkit as suggested solution, for this reason redux-rtk-effects is built on top of it, and fully compatible with its features.
In fact, the effects defined adhere to the Listener API exposed by Redux Toolkit, which covers several advanced side effects use cases, and support dependency injection by design.
A function that creates a store factory with the necessary middleware to handle effects.
Signature:
function createStoreFactory<
TState,
TAction extends Record<string, any>,
TEnvironment extends object
>(
config: {
initialState: TState;
actions: TAction;
environment: TEnvironment;
reducer: CustomReducer<TState, TAction, TEnvironment>;
}
): ReturnType<typeof _createStoreFactory<TState, TAction, TEnvironment>>;