
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
react-redux-patch
Advanced tools
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
npm install --save react-redux-patch
yarn add react-redux-patch
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 = new MicroModule('TheCoolKids', routes, reducers, AppContainer, 'root');
if (module.hot) {
module.hot.accept("@routes/index", () => {
microModule._render("@routes/index");
})
}
@AppContainer/index.js
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
export default class AppContainer extends Component {
static propTypes = {
cleanRoutes: PropTypes.array.isRequired,
history: PropTypes.object.isRequired,
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
]).isRequired
}
render() {
return (
<div>
{children}
</div>
);
}
}
@reducers/index.js
const common = (state = {}, action) => {
switch (action.type) {
default:
return state;
}
};
export default {
common
}
@routes/index.js
import DashboardPage from '@pages/dashboard/index.js'
const routes = [{
path: '/',
key: 'root',
component: Dashboard,
children: [{
path: '/dashboard',
key: 'dashboard',
component: DashboardPage
}]
}]
export default routes;
@pages/dashboard/index.js
import React, { Component } from "react";
import PropTypes from "prop-types";
const Actions = {
initialize: () => dispatch => {
dispatch({ type: "DASHBOARD/INITIALIZE" });
}
};
const INITIAL_STATE = {
name: "A sample Dashboard Page"
productName: "Macbook Pro",
discount: 0,
matches: []
};
const Reducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
default:
return state;
}
}
class DashboardPage extends Component {
static propTypes = {
/** Map prop with same name as
* propName i.e. state.dashboard.name
**/
@Prop
name: PropTypes.string
/** 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: PropTypes.number
/** 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
**/
@PropMapInit("interests")
matches: PropTypes.array
/** 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.
**/
@PropMapGlobal("state.application.name")
applicationName: PropTypes.string
/** All actions from Actions object will be available here!!
* no need to map them
**/
initialize: PropTypes.func.isRequired
}
render() {
return (
<>
<div>Sample Dashboard Page</div>
<pre>{JSON.stringify(this.props)}</pre>
</>
);
}
}
/** Returns a connected component
* and dynamically attaches reducer at state."dashboard" key
** /
export default StatefulComponent(DashboardPage, Actions, Reducer, "dashboard", false)
import React, { Component } from "react";
import { put, takeEvery, all } from 'redux-saga/effects'
import { WithSaga } from "react-redux-patch";
const delay = (ms) => new Promise(res => setTimeout(res, ms))
function* incrementAsync() {
yield delay(1000)
yield put({ type: 'INCREMENT' })
}
function* watchIncrementAsync() {
yield takeEvery('INCREMENT_ASYNC', incrementAsync)
}
// notice how we now only export the rootSaga
// single entry point to start all Sagas at once
function* rootSaga() {
yield all([
watchIncrementAsync()
])
}
Class ABC extends Component {
render() {
return (
<div>Sample Component</div>
);
}
}
WithSaga(ABC, rootSaga);
import React, { Component } from "react";
import PropTypes from "prop-types";
import { mapPropTypes, StatefulComponent, Prop, PropInit, PropMap, PropMapInit, PropMapGlobal } from "react-redux-patch";
const Actions = {
initialize: () => dispatch => {
dispatch({ type: "DASHBOARD/INITIALIZE" });
}
};
const INITIAL_STATE = {
name: "A sample Dashboard Page"
productName: "Macbook Pro",
discount: 0,
matches: []
};
const Reducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
default:
return state;
}
}
class DashboardPage extends Component {
static propTypes = {
name: PropTypes.string
itemName: PropTypes.string
discount: PropTypes.number
matches: PropTypes.array
applicationName: PropTypes.string
/** All actions from Actions object will be available here!!
* no need to map them
**/
initialize: PropTypes.func.isRequired
}
render() {
return (
<>
<div>Sample Dashboard Page</div>
<pre>{JSON.stringify(this.props)}</pre>
</>
);
}
}
mapPropTypes(DashboardPage, {
name: [Prop],
itemName: [PropMap, "productName"]
discount: [PropInit],
matches: [PropMapInit,"interests"],
applicationName: [PropMapGlobal,"state.application.name"]
});
/** Returns a connected component
* and dynamically attaches reducer at state."dashboard" key
** /
export default StatefulComponent(DashboardPage, Actions, Reducer, "dashboard", false)
import React, { Component } from "react";
import PropTypes from "prop-types";
import { mapStateProps, StatefulComponent, Prop, PropInit, PropMap, PropMapInit, PropMapGlobal } from "react-redux-patch";
const Actions = {
initialize: () => dispatch => {
dispatch({ type: "DASHBOARD/INITIALIZE" });
}
};
const INITIAL_STATE = {
name: "A sample Dashboard Page"
productName: "Macbook Pro",
discount: 0,
matches: []
};
const Reducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
default:
return state;
}
}
class DashboardPage extends Component {
static propTypes = {
name: PropTypes.string
itemName: PropTypes.string
discount: PropTypes.number
matches: PropTypes.array
applicationName: PropTypes.string
/** All actions from Actions object will be available here!!
* no need to map them
**/
initialize: PropTypes.func.isRequired
}
render() {
return (
<>
<div>Sample Dashboard Page</div>
<pre>{JSON.stringify(this.props)}</pre>
</>
);
}
}
mapStateProps(DashboardPage, (state, ownProps) => {
name: state.dashboard.name,
itemName: state.dashboard.productName,
discount: state.dashboard.discount,
matches: state.dashboard.interests,
applicationName: state.application.name
});
/** Returns a connected component
* and dynamically attaches reducer at state."dashboard" key
** /
export default StatefulComponent(DashboardPage, Actions, Reducer, "dashboard", false)
| 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 ```[]```` |
| 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 |
| Argument Name | Description | Optional |
|---|---|---|
| ReactComponent | Any base component before which saga is required | No |
| RootSagaFunc | A root saga function to be dynamically registered | No |
MIT © saurabhnemade
FAQs
>
The npm package react-redux-patch receives a total of 5 weekly downloads. As such, react-redux-patch popularity was classified as not popular.
We found that react-redux-patch demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.