synthetic-redux
v1.1.2
Published
Sets up Redux boilerplate: actions, reducers and redux-saga for most common redux use cases
Downloads
11
Maintainers
Readme
synthetic-redux
Sets up Redux boilerplate: actions, reducers and redux-saga for common API communication use cases
Given an action type and reducer key the library generates:
- Redux Actions: Success, Error & Reset action types
- Reducers: Updates Store with loading, success and error states
- Redux-Saga: Generates saga-effect that communicates with API and handles success and error responses
Purpose
An application can have multiple API calls. Redux + Redux-Saga is a popular tool to handle these side effects. The redux bits become repetitive over the numerous API calls. This library The use-case the library solves for is -
- API call needs to be made
- Success response should be reflected in the Redux Store
- Error response should be reflected in the Redux Store
- Reset action must be provided to reset the Redux Store
- Differentiate between Success and Error responses
- Handle exceptions in communication (eg. network error)
- Reflect exception in the Redux Store
Synthetic Redux
Provides an abstraction over 3 bits of boilerplate-ish code:
SyntheticAction
- Access to success, error & reset actions and their generatorsSyntheticReducers
- Access to loading, error and success States from Redux StoreSyntheticSaga
- Generates redux-saga effect that handles Success & Error API responses
API
Initialize =>
const synRedux = new SyntheticRedux(
{type: <action>, url: <string>, payload: <any> },
reducerKey
);
Cheatsheet
Kick off synthetic action =>
synRedux.ignite()
Access synthetic reducer =>
synRedux.reducer
Access synthetic sagaEffect =>
synRedux.sagaEffect
Set custom defaults for synthetic action(optional) =>
synRedux.ignite = (customUrl) => synRedux.actions.ignite({
url: customUrl,
errorHandler: (err) => CustomLogger.error(err)
});
Example Usage
const FETCH_TODOS = 'FETCH_TODOS';
const ADD_TODO = 'ADD_TODO';
export const listTodos = new SyntheticRedux({
payload: {filter: { isDeleted: false }},
type: FETCH_TODOS,
url: '/api/v1/todo/list',
}, 'list');
export const addTodo = new SyntheticRedux({
type: ADD_TODO,
url: '/api/v1/todo',
}, 'newTodo');
addTodo.igniteWrapper = payload => addTodo.actions.ignite({ payload });
// RootReducer.js
const RootReducer = combineReducers({
newTodo: addTodo.reducer,
todos: listTodos.reducer,
});
// RootSaga.js
export default function* RootSaga() {
const allSagas = [
addTodo.sagaEffect,
listTodos.sagaEffect,
]
yield all(allSagas.map(fork));
}
// React Component
export default TodoList = () => {
const listResponse = useSelector(state => state.todos.list);
const addResponse = useSelector(state => state.todos.newTodo)
const dispatch = useDispatch();
const onAdd = (payload) => {
dispatch(addTodo.igniteWrapper(payload));
};
React.useEffect(() => {
dispatch(listTodos.ignite());
}, [dispatch]);
React.useEffect(() => {
if(addResponse?.success) {
dispatch(addResponse.reset())
}
}, [dispatch])
if (listResponse[CATEGORY_NAMES].IGNITE) {
return <LoadingState/>;
} else if (listResponse.error) {
return <ErrorHandler error={listResponse.error}/>;
} else {
return <ShowTodos list={listResponse.list} onAdd={onAdd}/>;
}
};
// React Component
Customizing building blocks of Synthetic Redux:
Synthetic Actions
Redux requires actions as the basis of asynchronous communication. The modus operandi for redux actions is to define:
- an Action type (e.g. in
Type.js
) - a function that generates an object using
type: <action>
and some payload
Synthetic Actions take in a Base Action Type and generate:
<action>_SUCCESS
<action>_ERROR
<action>_RESET
types- functions that generate the desired Action Object
API
Kick off the action -> synAction.ignite();
Access base action string -> synAction.igniteName; // string
Access suffix actions -> synAction.suffixNames; // [string]
Access suffix action generators
-> synAction.suffixSyntheticActions; // [ { type: string, generator: fn } ]
Example
const FETCH_TODOS = 'FETCH_TODOS';
export const synAction = new SyntheticAction({
type: FETCH_TODOS,
url: '/api/v1/todo/list',
});
Synthetic Reducer
Companion reducer piece to SyntheticActions. Takes in a SyntheticAction and reducer key & returns Redux State handler.
Example
const synReducer = SyntheticReducer(synAction, 'list')
const RootReducer = combineReducers({
todos: synReducer
});
/* Usage in React Component */
const listResponse = useSelector(state => state.todos.list);
if (listResponse[CATEGORY_NAMES].IGNITE) { return <LoadingState />; }
else if (listResponse.error) { return <ErrorHandler error={listResponse.error} />; }
else { return <ShowTodos list={listResponse.list} />; }
Synthetic Redux-Saga Effect
Companion redux-saga with SyntheticActions and SyntheticReducer Given a SyntheticAction it returns a sagaEffect. The sagaEffect comes embedded with Error & Success Handling
Opinions
- Uses
takeLatest
to execute the effect - Requires the API to respond with
{ error: <any> }
to indicate error - Expects action to be set with an
url
andpayload(opt)
for the API call
API
const sagaEffect = SyntheticSagaEffect(synAction);
const todoSaga = yield all([sagaEffect]);
export default function* RootSaga() {
const allSagas = [todoSaga];
yield all(allSagas.map(fork));
}