redux-butler v1.1.3
Redux Butler
Inspired by reduxsauce, Redux Butler was designed to make working with Redux and Immer even more simple and convenient.
- ✨ Create actions in seconds with just a tiny configuration object
- 😱 Action types (enumeration) are generated automatically
- 😅 Say goodbye to painfully returning state copies with endless spreads
- 🙌 Create reducers using Immer with a just tiny configuration object
- 🥳 Works wherever Redux works (yes, also with React and React Native)
- 🥳 No dependencies except Immer
- 😎 Short plain vanilla code
- ✅ Well tested with Jest
When is Redux Butler for me?
- If you are tired creating Redux actions (with repeating creator pattern and endless type enumerations) and reducers (with endless switch statements) the exhausting way
- If you want to make use of immutability the easy way incorporating incredible Immer in your project
Getting started
Install Redux Butler:
$ yarn add redux-butler
# or
$ npm install redux-butler
Usage
Redux Butler currently offers the two methods createActions
and createReducer
.
createActions
// actions.js
import { createActions } from 'redux-butler';
export const { Types, Creators } = createActions({
reset: null,
loginRequest: ['email', 'password'],
requestWithDefaultValues: { email: 'joey@example.com', password: '123' },
custom: (a, b) => ({ total: a + b }),
},{}); // 2nd parameter is for options
The keys of the object will become keys of the Creators
. They will also become the keys of the Types
after being converted to SCREAMING_SNAKE_CASE 😱🐍. The values will control the flavour of the action creator.
Action creators with type only
When null is passed, the action creator will only have a type. Example:
creators.reset() // { type: 'RESET}
Action creators with params
When params are passed as an array of strings, an action creator will have a type and return a function with two params. Example:
creators.loginRequest('joey@example.com', '123');
// { type: 'LOGIN_REQUEST', email: 'joey@example.com', password: '123' }
Action creators with defaults
When params are passed with defaults in form of an object, an action creator will have a type and return a function with two defaulted params. Example:
creators.requestWithDefaultValues();
// { type: 'REQUEST_WITH_DEFAULT_VALUES', email: 'joey@example.com', password: '123' }
creators.requestWithDefaultValues('john.doe@example.com', '456');
// { type: 'REQUEST_WITH_DEFAULT_VALUES', email: 'john.doe@example.com'', password: '456' }
Action creators with custom functions
When a custom function is passed, the action behaves the default redux way. Type is created automatically.
Options
As options currently only the key prefix
is valid. Example:
// createActions with prefix option
export const { Types, Creators } = createActions({
loginRequest: ['email', 'password'],
},{ prefix: 'auth'});
// will result in
Creators.authLoginRequest('joey@example.com', '123');
// { type: 'AUTH_LOGIN_REQUEST', email: 'joey@example.com', password: '123' }
Types.AUTH_LOGIN_REQUEST
// 'AUTH_LOGIN_REQUEST'
createReducer
// reducer.js
import { createReducer } from 'redux-butler';
import { Types } from './actions';
const intitialState = { email: null, password: null };
// Sample reducer function
const loginRequest = (action, draft) => {
const { email, password } = action;
draft.email = email;
draft.password = password;
};
// Map Action Types to reducer functions in the handler object
const handlers = {
[Types.RESET]: null,
[Types.LOGIN_REQUEST]: loginRequest,
};
const reducer = createReducer(intitialState, handlers);
export default reducer;
Easy as pie. Define an initial state (as you would do anyway), create a tiny handler object and inject into the createReducer
function. You may just export the reducer or even merge multiple reducers with Redux's combineReducers()
.
Handlers with null
are reset handlers
E.g. [Types.RESET]: null
will return the initial state as new state (reset). No more need to write a reset function.
Handlers with (action, draft) => {}
functions
Those are the regular reducer functions with Redux Butler. action
will make your payload accessible, while draft
represents current state, that will be returned as the next state, using Immer's produce()
behind the scenes. Just modify draft to your taste. That's it!