Reduxed is a Redux helper library for creating type constants, actions, reducers and more without all Redux boilerplate.
Because Redux has a lot of boilerplate and we always see ourselves doing repetitive tasks like:
- Creating action type constants
- Creating action creators
- Creating reducers with lots of
switch
case
statements - Splitting all these things in many files (actions.js, types.js, reducer.js, constants.js, etc...)
Or sometimes we need a way to reuse reducers logic and Redux don't provides a native way to do this.
Reduxed solves the above problems.
You can read a more in-depth introduction about Reduxed in the article below:
Reduxed - Reduced Redux Boilerplate
npm install --save reduxed
Let's see an example without Reduxed.
// types
export const INCREMENT = 'app/counter/increment';
export const DECREMENT = 'app/counter/decrement';
// action creators
export const increment = (value = 1) => ({ type: INCREMENT, payload: value });
export const decrement = (value = 1) => ({ type: DECREMENT, payload: value });
const initialState = 0;
// reducer
export const reducer = (state = initialState, action) => {
switch (action.type) {
case INCREMENT:
return state + action.payload;
case DECREMENT:
return state - action.payload;
default:
return state;
}
}
Now let's see the same using Reduxed:
import { create, handler, getActions, getReducer, getTypes } from "reduxed";
const initialState = 0;
const options = { typePrefix: "app/counter" };
const counter = create(
handler("increment", (state, payload = 1) => state + payload),
handler("decrement", (state, payload = 1) => state - payload)
)(initialState, options); // options are optional
export const reducer = getReducer(counter);
export const actions = getActions(counter);
export const types = getTypes(counter);
Then you can use your reducer, actions and types like you normally do.
getReducer
will return a Redux like reducer function that accepts a state and action as arguments:
reducer(1, { type: 'app/counter/INCREMENT' }) // 2
getActions
will return an object like the following:
{
increment: payload => ({ type: 'app/counter/INCREMENT', payload }),
decrement: payload => ({ type: 'app/counter/DECREMENT', payload }),
}
getTypes
will return an object like the following:
{
increment: 'app/counter/INCREMENT',
decrement: 'app/counter/DECREMENT',
}
If you need to reuse reducers logic across your application you can use withScope
from Reduxed:
import { combineReducers } from 'redux';
import { withScope } from 'reduxed';
import { reducer } from './counter';
const rootReducer = combineReducers({
counterA: withScope('A', reducer),
counterB: withScope('B', reducer),
counterC: withScope('C', reducer),
});
Then in your mapDispatchToProps you can do something like this:
import { withScope } from 'reduxed';
import { bindActionCreators } from 'redux';
import { actions } from './counter';
const mapDispatchToProps = (dispatch, ownProps) => {
const scopedActions = withScope(ownProps.scope, actions);
return bindActionCreators(scopedActions, dispatch);
}
In your components:
const Counters = () => (
<div>
<Counter scope="A" />
<Counter scope="B" />
<Counter scope="C" />
</div>
);
Simple counter:
Multiple counters with scope: