redux-direct v1.0.0
redux-direct
Use Redux without string constants.
With redux-direct you can use your action creators directly inside the reducers instead of having to define string constants for each action.
Usage
Each action creator created by redux-direct has a toString()
method that returns the action type. Combined with ES6 computed properties this allows you to write the following code:
import { createAction, createReducer } from 'redux-direct';
const increment = createAction('INCREMENT');
const decrement = createAction('DECREMENT');
const reducer = createReducer(initialState, {
[increment]: (state, action) => ({ ...state, counter: state.counter++ }),
[decrement]: (state, action) => ({ ...state, counter: state.counter-- }),
});
Action Payload
By default, the first argument passed to an action creator is used as payload
, the second as meta
. Calling increment(2, { foo: 'bar' })
will create the following action:
{
type: 'INCREMENT',
payload: 2,
meta: {
foo: 'bar',
},
}
You can dynamically create payloads by providing a payload creator function:
createAction('INCREMENT' by => by || 1);
An additional third argument can be specified to provide predefined meta data. To dynamically create the data you can pass a function that will be called with the same arguments as the payload creator.
Multiple Actions
Usually you want to create multiple actions at once:
import { createActions } from 'redux-direct';
export default createActions('counter', {
increment: by => by || 1, // payload creator
decrement: { // payload and meta
payload: by => by || 1,
meta: 'foo',
},
reset: false, // use action arguments as payload and meta
});
This will create actions with the types COUNTER_INCREMENT
, COUNTER_DECREMENT
and COUNTER_RESET
.
You can also use a path like __filename
as prefix, in which case the file's basename (without the extension) is used.
Action Phases
If you use a middleware like redux-promised, redux-async or redux-promise-middleware that dispatches multiple actions with different suffixes, you can specify a handler for each suffix in your reducer:
createReducer(initialState, {
[loadUser]: {
_PENDING: (state, action) => ({ ...state, user: null, error: null }),
_RESOLVED: (state, action) => ({ ...state, user: action.payload }),
_REJECTED: (state, action) => ({ ...state, user: null, error: action.payload }),
}
});
Some middleware implementations like redux-simple-promise dispatch an action without any suffix for the pending state. Since redux-direct uses the same method to build the final action types as it does in createActions()
the following definition can be used:
const loadUser = createAction('LOAD_USER');
createReducer(initialState, {
[loadUser]: {
_: (state, action) => (/* LOAD_USER */),
resolved: (state, action) => (/* LOAD_USER_RESOLVED */),
rejected: (state, action) => (/* LOAD_USER_REJECTED */),
}
});
API
createAction
createAction(type, [payloadCreator], [metaCreator])
Returns a function that creates FSA compliant actions of the given type. See usage for a basic example.
createActions
createActions([prefix], definition)
Returns an object with methods to create the described actions. See Multiple Actions for an example.
createReducer
createReducer(initialState, handlers)
Returns a reducer function. See usage for a basic example or Action Phases for a more advanced use case.
License
MIT