synthetic-redux v1.1.2
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: 1. Redux Actions: Success, Error & Reset action types 2. Reducers: Updates Store with loading, success and error states 3. 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 - 1. API call needs to be made 2. Success response should be reflected in the Redux Store 3. Error response should be reflected in the Redux Store 4. Reset action must be provided to reset the Redux Store 5. Differentiate between Success and Error responses 6. Handle exceptions in communication (eg. network error) 7. Reflect exception in the Redux Store
Synthetic Redux
Provides an abstraction over 3 bits of boilerplate-ish code:
1. SyntheticAction
- Access to success, error & reset actions and their generators
2. SyntheticReducers
- Access to loading, error and success States from Redux Store
3. SyntheticSaga
- 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:
1. an Action type (e.g. in Type.js
)
2. a function that generates an object using type: <action>
and some payload
Synthetic Actions take in a Base Action Type and generate:
1. <action>_SUCCESS
<action>_ERROR
<action>_RESET
types
2. 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));
}
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago