npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-redux-patch

v1.0.6

Published

>

Downloads

15

Readme

react-redux-patch

NPM JavaScript Style Guide

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 = new MicroModule('TheCoolKids', routes, reducers, AppContainer, 'root');

if (module.hot) {
  module.hot.accept("@routes/index", () => {
    microModule._render("@routes/index");
  })
}

Creating App Container

@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>
        );
    }
}

Creating Root Reducers

@reducers/index.js

const common = (state = {}, action) => {
    switch (action.type) {
      default:
        return state;
    }
};

export default {
  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
    }]
}]

export default routes;

StatefulComponent: connect, mapStateToProps and mapDispatchToProps Abstraction

@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)

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) => 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);

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 = {
    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)

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 = {
    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)

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