atomic-redux
v0.0.0
Published
[![Build Status](https://travis-ci.org/brietsparks/atomic-redux.svg?branch=master)](https://travis-ci.org/brietsparks/atomic-redux) [![npm version](https://badge.fury.io/js/atomic-redux.svg)](https://badge.fury.io/js/atomic-redux) [![Coverage Status](http
Downloads
2
Readme
Atomic Redux
This library cuts down on boilerplate of writing reducers and action-creators for collection-based state. The goal is to make it easier to create and work with normalized state trees.
The idea behind atomic Redux is to limit a collection reducer to basic or "atomic" operations - set, add, remove, and replace. For example:
const itemsReducer = (items = [], { type, payload }) => {
switch (type) {
case 'SET_ITEMS': return payload.items;
case 'ADD_ITEM': return addItemToItems(payload.item, items)
case 'REMOVE_ITEM': return removeItemFromItems(payload.itemId, items)
case 'REPLACE_ITEM': return replaceItemInItems(payload.item, items)
default: return items
}
}
Each atomic operation gets an action creator:
const setItems = items => ({ type: 'SET_ITEMS', payload: items })
const addItem = (id, item) => ({ type: 'ADD_ITEM', payload: { id, item } })
const removeItem = id => ({ type: 'REMOVE_ITEM', payload: id })
const replaceItem = (id, item) => ({ type: 'REPLACE_ITEM', payload: { id, item } })
Then, you can combine atomic action creators to make complex action creators:
// with redux-thunk
const upsertItem = (item) => {
return dispatch => {
const action = item.id ? replaceItem(item.id, item) : addItem(item);
dispatch(action);
}
}
As shown, atomic reducer operations provide some nice benefits:
- an easy API to define how a collection state reduces
- simple and closed set of reductions = no accidental state mutation
- clear separation between state management and "business logic"
- no need to write hairy object manipulation code in the reducer
This library comes into play by providing a utility function to create an atomic reducer and its action creators. And if you keep each collection flat, they can be associated through foreign-key-like identifier fields, similar to a relational database, and you will have achieved a normalized Redux state.
Installation
yarn add atomic-redux
Usage
Two utility functions are provided:
createArrayModule
: use this if your collection substate is an arraycreateObjectModule
: use this if your collection substate is an object-literal (key-value map)
createArrayModule
Use this if your collection substate is an array.
import { createArrayModule } from 'atomic-redux';
import types from './actionTypes';
const { reducer, actionCreators } = createArrayModule({
setAction: types.SET_CHICKENS,
addAction: types.ADD_CHICKEN,
removeAction: types.REMOVE_CHICKEN,
replaceAction: types.REPLACE_CHICKEN,
});
It will return 4 action creators:
const { setItems, addItem, removeItem, replaceItem } = actionCreators;
Assign them to variables with appropriate names for your use case:
const setChickens = actionCreators.setItem;
const addChicken = actionCreators.addItem;
const removeChicken = actionCreators.removeItem;
const replaceChicken = actionCreators.replaceItem;
And then use them like this:
setChickens([
{ id: 1, name: 'Beeky' },
{ id: 2, name: 'Bert' }
]);
addChicken({ id: 3, name: 'Wingz' })
removeChicken(2);
replaceChicken(1, { id: 1, name: 'Nuggy' })
createObjectModule
Use this if your collection substate is an object-literal (key-value map)
import { createObjectModule } from 'atomic-redux';
import types from './actionTypes';
const { reducer, actionCreators } = createObjectModule({
setAction: types.SET_CHICKENS,
addAction: types.ADD_CHICKEN,
removeAction: types.REMOVE_CHICKEN,
replaceAction: types.REPLACE_CHICKEN,
});
It will return 4 action creators:
const { setItems, addItem, removeItem, replaceItem } = actionCreators;
Assign them to variables with appropriate names for your use case:
const setChickens = actionCreators.setItem;
const addChicken = actionCreators.addItem;
const removeChicken = actionCreators.removeItem;
const replaceChicken = actionCreators.replaceItem;
And then use them like this:
setChickens({
1: { id: 1, name: 'Beeky' },
2: { id: 2, name: 'Bert' }
});
addChicken(3, { id: 3, name: 'Wingz' })
removeChicken(2);
replaceChicken(1, { id: 1, name: 'Nuggy' })
Options
Custom key for array-based state items: In createArrayModule
, by default,
the replace and remove operations will look for id
as the key on each object.
To change this, pass a callback to the utility function:
const { reducer, actionCreators } = createArrayModule({
// ...
getKey: item => item.myCustomId
});