trampss-redux-data-store
v4.1.0
Published
Factory of Redux reducers and their associated actions and selectors. > Make your Redux code base tinier and simpler to maintain
Downloads
1
Readme
trampss-redux-data-store
Factory of Redux reducers and their associated actions and selectors.
Make your Redux code base tinier and simpler to maintain
Contents
Purpose
trampss-redux-data-store
creates generic reducers, actions and selectors in two lines.
import factory from 'trampss-redux-data-store'
export default factory(/* middlewares */)('id')('api')('todos')
That's it, you exported a reducer function you can register thanks to combinerReducer in Redux.
In this example, we have a todos
reducer, it has to be combined into state.api.todos
Why
We like to write Redux code as simple as possible and use its middlewares to handle real world problems. From this point of view, our Redux code base simpler : it's like a key/value store. But one drawback is the amount of duplicated code, each resource has its own reducers, actions and selectors.
To avoid Redux code base from growing, inconsistency and lowering maintainability, we created this lightweight library (<4Kb) that is a factory of reducers, actions and selectors.
Installation
yarn add trampss-redux-data-store
npm i trampss-redux-data-store
peer dependency
lodash
: we use the minimum of lodash function trying to have a lightweight webpack bundle.keyBy
without
uniq
omit
at
API
factory
You need to use the factory to get a new set of reducer/actions/selectors :
import factory from 'trampss-redux-data-store'
This factory takes four parameters, you could use between these signatures :
factory(middlewares, fieldKey, path, name)
factory(middlewares, fieldKey, path)(name)
factory(middlewares, fieldKey)(path)(name)
factory(middlewares)(fieldKey)(path)(name)
Parameters are :
- middlewares (optional), contain an object with
pre
andpost
fields. Both are an array of middlewares to apply before and after thecore
middleware. - fieldKey (mandatory), the field used to identify your objects (
id
for example)- you have to set this parameter.
- path (optional), where the reducer will be combined via
combineReducer
- if empty
export default factory('id')()('todos')
, the reducer will be register ate the root level of the redux state - you can use dot notation, like
api.raw
: your reducer will be combined intostate.api.raw.<your_reducer>
- if empty
- name (mandatory), the reducer name (for instance:
todos
)- it's used to generate actions types
- it's used to retrieve informations from selectors
Example:
- this reducer will use
id
as key field - it's combined into
state.api.raw
- its name is
todos
import factory from 'trampss-redux-data-store'
// factory(fieldKey)(path)(name)
export default factory()('id')('api.raw')('todos')
Data will be stored into state.api.raw.todos
reducer
The previous factory returns a function which is a reducer. You just have to combine it like any other reducer :
import { createStore, combineReducers, compose, applyMiddleware } from 'redux'
// import your reducer
// (created by tramps-redux-data-store factory)
import todos from './myTodosReducer'
// create your Redux store as usual
const store = createStore(
combineReducers({
// [other reducer]
api: combineReducers({
// [other reducer]
raw: combineReducers({
// import your reducer into api.raw
// since we configured this path
todos,
}),
// [other reducer]
}),
// [other reducer]
}),
/* your Redux middlewares */
)
export default store
actions
The factory returns a function (this is the reducer) that also contains actions and selectors as fields. Some generic actions are available. By now, it's not possible to add custom ones.
Actions are:
| function name | description | signature | generated action |
|---|---|---|---|
| set
| set an array of instances of your resource | set(<array>)
| { type: '@trampss/SET_TODOS', payload: <array> }
|
| add
| add an instance of your resource | add(<instance>)
| { type: '@trampss/ADD_TODOS', payload: <instance> }
|
| remove
| remove one instance of your resource by its key | remove(<key>)
| { type: '@trampss/REMOVE_TODOS', payload: <key> }
|
| reset
| reset the reducer (wipe all data) | reset()
| { type: '@trampss/RESET_TODOS' }
|
Example, we set todos to our reducer:
// import your reducer
// (created by tramps-redux-data-store factory)
import todos from './myTodosReducer'
// dispatch can be given by one of your middleware (redux-thunk, redux-saga, etc)
// or it can be given by react-redux for example (mapDispatchToProps)
dispatch(
// set todos
todos.set([
{
id: '1', // we set 'id' as key in the factory
visible: true,
label: 'My first todo',
},
{
id: '2',
visible: false,
label: 'This todo is done',
},
])
)
selectors
The factory returns a function (this is the reducer) that also contains actions and selectors as fields. Some generic selectors are available. By now, it's not possible to add custom ones.
Selectors are:
| signature | description | comment |
|---|---|---|
| get(<id>)(state)
| returns all data, or specific(s) one(s) (by key(s)) | if <id>
is undefined
, it returns all dataif <id>
is an array, it returns all instances that match one of idsin other cases, it returns the instance with its id
that that match the parameter |
| getBy(<propertyPath>, <value>)(state)
| get data specified by the field you want to filter with (take care, selectors are not memoized) | Example: getBy('visible', true)(state)
returns all visible todos.
| getKeys(state)
| returns all store keys (in array) | |
| getAsArray(state)
| returns all data in array (raw) | |
| getLength(state)
| returns number of stored instances | |
| isInitialized(state)
| return true if the store has been initialized (by add
or by set
action) | |
| getState(state)
| returns the global state of your reducer | The global state contains :data
: key/value storearray
: raw datakeys
: keys arrayinitialized
: boolean (set to true by set
and add
actions)
Example, we retrieve the todo with id 1
:
// import your reducer
// (created by tramps-redux-data-store factory)
import todos from './myTodosReducer'
// state can be given by one of your middleware (redux-thunk, redux-saga, etc)
// or it can be given by react-redux for example (mapStateToProps)
todos.get('1')(state)