react-redux-patch
What is react-redux-patch?
react-redux-patch is just another library which tries to simplify the web application development for react applications. From various ideas I came across past few years and a few implementations which I think are founding ground for this project, I decided to write this library to abstract the general setup of react-redux application. It specifically focuses and solves the problem of registering dynamic reducers. It also provides shorthand syntax for connect, mapStateToProps and mapDispatchToProps
Install
npm install --save react-redux-patch
yarn add react-redux-patch
Usage
Creating a module
index.js
import MicroModule from 'react-redux-patch';import AppContainer from '@AppContainer/index.js';import routes from '@routes/index.js';import reducers from '@reducers/index.js'; const microModule = 'TheCoolKids' routes reducers AppContainer 'root'; if modulehot modulehot
Creating App Container
@AppContainer/index.js
import React PureComponent from 'react';import PropTypes from 'prop-types'; static propTypes = cleanRoutes: PropTypesarrayisRequired history: PropTypesobjectisRequired children: PropTypesisRequired { return <div> children </div> ; }
Creating Root Reducers
@reducers/index.js
const common = state = action switch actiontype default: return state; ; common
Creating Routes
@routes/index.js
import DashboardPage from '@pages/dashboard/index.js' const routes = path: '/' key: 'root' component: Dashboard children: path: '/dashboard' key: 'dashboard' component: DashboardPage ;
StatefulComponent: connect, mapStateToProps and mapDispatchToProps Abstraction
@pages/dashboard/index.js
import React Component from "react";import PropTypes from "prop-types"; const Actions = { ; }; const INITIAL_STATE = name: "A sample Dashboard Page" productName: "Macbook Pro" discount: 0 matches: ; const Reducer = state = INITIAL_STATE action switch actiontype default: return state; static propTypes = /** Map prop with same name as * propName i.e. state.dashboard.name **/ @Prop name: PropTypesstring /** Map Prop with differnt name in state * i.e. state.dashboard.product @PropMap("productName") itemName: PropTypes.string /** Map prop with same name as propName * but update its initial value in store * in this case state.dashboard.discount will be mapped. * Before mapping it will update passed value in state. **/ @PropInit discount: PropTypesnumber /** Map prop with different name in state * but update its initial value in store * in this case state.dashboard.matches will be mapped. * Before mapping it will update passed value in state **/ @ matches: PropTypesarray /** Map prop with absolute given key path in state * i.e. state outside of this component * Its usage is to access the global state objects that created in root reducers. * In this case state.application.name will be mapped. **/ @ applicationName: PropTypesstring /** All actions from Actions object will be available here!! * no need to map them **/ initialize: PropTypesfuncisRequired { return <> <div>Sample Dashboard Page</div> <pre>JSON</pre> </> ; } /** Returns a connected component * and dynamically attaches reducer at state."dashboard" key ** /export default StatefulComponent(DashboardPage, Actions, Reducer, "dashboard", false)
WithSaga: Dynamically register saga in application
import React Component from "react";import put takeEvery all from 'redux-saga/effects'import WithSaga from "react-redux-patch"; const delay = ms { } { } // notice how we now only export the rootSaga// single entry point to start all Sagas at once { } Class ABC extends Component { return <div>Sample Component</div> ; } ;
StatefulComponent: connect, mapStateToProps and mapDispatchToProps Abstraction
Without Decorator Support
## Method 1: mapPropTypes - If PropTypes are being used
import React Component from "react";import PropTypes from "prop-types";import mapPropTypes StatefulComponent Prop PropInit PropMap PropMapInit PropMapGlobal from "react-redux-patch"; const Actions = { ; }; const INITIAL_STATE = name: "A sample Dashboard Page" productName: "Macbook Pro" discount: 0 matches: ; const Reducer = state = INITIAL_STATE action switch actiontype default: return state; static propTypes = name: PropTypesstring itemName: PropTypesstring discount: PropTypesnumber matches: PropTypesarray applicationName: PropTypesstring /** All actions from Actions object will be available here!! * no need to map them **/ initialize: PropTypesfuncisRequired { return <> <div>Sample Dashboard Page</div> <pre>JSON</pre> </> ; } ; /** Returns a connected component * and dynamically attaches reducer at state."dashboard" key ** /export default StatefulComponent(DashboardPage, Actions, Reducer, "dashboard", false)
Method 2: mapStateProps - If PropTypes are optional or you like to use some enhancers like selectors
import React Component from "react";import PropTypes from "prop-types";import mapStateProps StatefulComponent Prop PropInit PropMap PropMapInit PropMapGlobal from "react-redux-patch"; const Actions = { ; }; const INITIAL_STATE = name: "A sample Dashboard Page" productName: "Macbook Pro" discount: 0 matches: ; const Reducer = state = INITIAL_STATE action switch actiontype default: return state; static propTypes = name: PropTypesstring itemName: PropTypesstring discount: PropTypesnumber matches: PropTypesarray applicationName: PropTypesstring /** All actions from Actions object will be available here!! * no need to map them **/ initialize: PropTypesfuncisRequired { return <> <div>Sample Dashboard Page</div> <pre>JSON</pre> </> ; } ; /** Returns a connected component * and dynamically attaches reducer at state."dashboard" key ** /export default StatefulComponent(DashboardPage, Actions, Reducer, "dashboard", false)
API
MicroModule(name, routes, reducers, appContainer, containerId , userSpecifiedMiddleWares)
Argument Name | Sample value | Description | Optional |
---|---|---|---|
name | "Slack" |
Name of module | No |
routes | `const routes = [{``` | Routes for application | No |
path: '/', |
|||
key: 'root', |
|||
component: Dashboard, |
|||
children: [{ |
|||
path: '/dashboard', |
|||
key: 'dashboard', |
|||
component: DashboardPage |
|||
}] |
|||
}] |
|||
reducers | const rootReducers = { }; |
Global root reducers if you want to abstract stuff like notifications | No |
appContainer | const appContainer=({props,cleanRoutes}) => (<>{this.props.children</>) |
App Container where your routes will render. You can customise things like custom header before routes. | No |
containerId | root |
Dom element id in which app will be render | Yes. Defaults to root |
userSpecifiedMiddleWares | Additional redux middlewares that you need added | Yes. Defaults to ```[]```` |
StatefulComponent(ReactComponent, Actions, Reducer, DynamicStateName, Inherit?)
Argument Name | Default value | Description | Optional |
---|---|---|---|
ReactComponent | (<></>) | A react component which needs to be connected | No |
Actions | {} | Actions object that will be used in dynamically created mapDispatchToProps | No |
Reducer | (state) => { return state } | Reducer that needs to be dynamically registered against DynamicStateName | No |
DynamicStateName | '\_' + Math.random().toString(36).substr(2, 9) |
A dynamic state key where reducer will be attached | No |
Inherit | false | Whether to create the state dynamically inside another state key generated by StatefulComponent | Yes |
WithSaga(ReactComponent, RootSagaFunc)
Argument Name | Description | Optional |
---|---|---|
ReactComponent | Any base component before which saga is required | No |
RootSagaFunc | A root saga function to be dynamically registered | No |
License
MIT © saurabhnemade