uptrend-redux-modules
Redux Module (redux + redux-saga + redux-saga-thunk) for requesting resources from API and storing response data into entities if provided a normalizr schema.
Loading...
The problem
At Uptrend we enjoy building React applications and have had success using redux + normalizr to manage state and redux-saga + redux-saga-thunk to orchestrate application side effects (i.e. asynchronous things like data fetching). Code is easy to understand and typically works as expected but someone could have a criticism about the amount of ceremony and boilerplate required.
Typically, whenever adding a new entity to an app it required us to write reducers, actions, sagas, schemas, selectors, and container components to get basic CRUD functionality.
This solution
Create a concise and straightforward way to make HTTP requests that normalize response handling including normalization of response data into index entities in the redux store. To get CRUD functionality for a new entity, you add a normalizr schema and use the provided actions and selectors provided by URM (uptrend-redux-modules). URM also provides render prop React components that simplify and reduce the amount of code needed.
Below are code examples to highlight what using URM resource and entities looks like:
ResourceDetailLoader Component
const OrgDetailAutoLoader = <ResourceDetailLoader resource="org" resourceId=orgId autoLoad> <div> <pre>'autoLoad={true}'</pre> <button onClick=onEventLoadResource disabled=statusloading> Load Resource </button> statusinitial && <span className="label label-default">initial</span> statusloading && <span className="label label-primary">loading</span> statuserror && <span className="label label-danger">error</span> statussuccess && <span className="label label-success">success</span> statusloading ? <h5>Loading...</h5> : result && <div> <div> Org ID: <code>resultid</code> </div> <div> Active: <code>resultactive ? 'Yes' : 'No'</code> </div> </div> </div> </ResourceDetailLoader>
ResourceListLoader Component
const OrgListLoader = <ResourceListLoader resource="org"> <div> <div> <pre>'autoLoad={false}'</pre> <pre>JSON</pre> </div> <button onClick=onEventLoadResource disabled=statusloading> Load Resource </button> statusinitial && <span className="label label-default">initial</span> statusloading && <span className="label label-primary">loading</span> statuserror && <span className="label label-danger">error</span> statussuccess && <span className="label label-success">success</span> statusloading ? <h5>Loading...</h5> : result && result </div> </ResourceListLoader>
Using Resource Redux-Saga-Thunk Style
Resource actions provide a promise based interface that redux-saga-thunk
allows. Below shows how a resource can use without using selectors. This is nice
when you need resource data to save locally.
const mapDispatchToProps = Component state = loading: false groupList: null { this } { this thisprops } { this } { this } { const loading groupList = thisstate if loading return <div>Loading...</div> return <ul>groupList</ul> } GroupListContainerpropTypes = fetchTripGroupList: PropTypesfuncisRequired null mapDispatchToPropsGroupListContainer
Redux Modules
There
// TODO
Table of Contents
Installation
This module is distributed via npm which is bundled with node and
should be installed as one of your project's dependencies
:
yarn add uptrend-redux-modules
Example Project Usage
Below is an example of how one may set it up in a react app using the resource and entities redux-modules.
Do note there are many ways you could organize your project and this example is not strict guidelines by any means.
Resource & Entities
-
src/store/modules/resource/index.js
// - src/store/modules/resource/index.js// createResource(...) => { actions, reducers, sagas, selectors } -
src/store/modules/entities/index.js
// - src/store/modules/entities/index.js// createEntities(...) => { actions, middleware, reducers, sagas, selectors }schemas -
src/store/modules/entities/schema.js
// - src/store/modules/entities/schemas.jsconst user = 'users'const team = 'teams' owner: user members: user -
src/store/actions.js
// - src/store/actions.js;; -
src/store/middlewares.js
// - src/store/middlewares.js// redux-modules middlewaresentities
-
src/store/reducers.js
// - src/store/reducer.jsentitiesresource -
src/store/sagas.js
// - src/store/sagas.js// single entry point to start all Sagas at once{trycatch errorconsoleconsole} -
src/store/selectors.js
// - src/store/selectors.js
Usage
// TODO
Inspiration
Organizing actions, reducers, selectors, sagas, etc. into a module is based on redux-modules from Diego Haz.
The resource and entities modules specifically are modified version of those found in redux-modules and ARc.js.
Other Solutions
I'm not aware of any, if you are please make a pull request and add it here!
Contributors
Brandon Orther 💻 🚇 ⚠️ 💡 |
Dylan Foster 🐛 🤔 |
---|
Thanks goes to these people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!
LICENSE
MIT