react-reducer-provider.github.io

Asynchronous/Synchronous React Centralized State

Follow me on GitHub

Asynchronous/Synchronous React Centralized State

with Hooks and HOC

through Centralized Reducers/Mappers/Actuators

Flux/Redux made Easy, Simple and Beyond

react-reducer-provider react-reducer-provider      License   Github repo Gitlab repo


react-reducer-provider provides a centralized state, managed asynchronously or synchronously through a reducer, mapper or actuator.


Quick Start

1 . Add dependency:

package.json:

when using hooks:

  ..
  "dependencies": {
    "react": ">=16.8.0"
    "react-reducer-provider": "5.1.0",
    ..

when using HOC:

  ..
  "dependencies": {
    "react": ">=16.0.0"
    "react-reducer-provider": "5.1.0",
    ..

Reducers

2 . Create the AsyncReducerProvider or SyncReducerProvider component to manage the centralized state:

Reducers

a . Define the initial state.
b . Define the reducer function.
c . Define the Reducer Provider.

SomeReducerProvider.jsx:

import React from 'react'
import { SyncReducerProvider } from 'react-reducer-provider'

const initialState = 0

function reduce(prevState, action, delta) {
  switch (action) {
    case 'ACTION1':
      return prevState + delta
    case 'ACTION2':
      return prevState - delta
    default:
      return prevState
  }
}

function SomeReducerProvider({ children }) {
  return (
    <SyncReducerProvider
      reducer={reduce}
      initialState={initialState}
    >
      {children}
    </SyncReducerProvider>
  )
}

export default SomeReducerProvider

3 . Access the state and the dispatcher of the Provider component using the hooks or HOC provided by 'react-reducer-provider':

Dispatcher

SomeComponent1.jsx => using useReducer:

import { useReducer } from 'react-reducer-provider'
import React from 'react'

export default function SomeComponent1() {
  const { state, dispatch } = useReducer()
  return (
    <button onClick={() => dispatch('ACTION1', 2)}>
      Go up (from {state})!
    </button>
  )
}

SomeComponent2.jsx => using injectReducerDispatcher:

import { injectReducerDispatcher } from "react-reducer-provider";
import React from "react";

class SomeComponent2 extends React.Component {
  render() {
    return (
      <button onClick={() => {
        const newState = dispatch('ACTION2', 1)
        console.info(newState)
      }}>
        Go down!
      </button>
    )
  }
}

export default injectReducerDispatcher(SomeComponent2, 'dispatch')

SomeComponentN.jsx => using useReducerState:

import { useReducerState } from 'react-reducer-provider'
import React from 'react'

export default function SomeComponentN() {
  const currentState = useReducerState()
  return (
    <div>
      Current:{currentState}
    </div>
  )
}

4 . Wrap components which will consume the SomeReducerProvider component:

SomeContainer.jsx:

import SomeComponent1 from './path/to/SomeComponent1'
import SomeComponent2 from './path/to/SomeComponent2'
import SomeComponentN from './path/to/SomeComponentN'
import SomeReducerProvider from '../path/to/SomeReducerProvider'
import React from 'react'

export default function SomeContainer() {
  return (
    <SomeReducerProvider>
      <SomeComponent1/>
      <SomeComponent2/>
      <SomeComponentN/>
    </SomeReducerProvider>
  )
}

SomeContainer

This SyncReducerProvider example can be checked on line at gmullerb-react-reducer-provider codesandbox: Edit gmullerb-react-reducer-provider
This SyncReducerProviderwith HOC example can be checked on line at gmullerb-react-reducer-provider codesandbox:
Edit gmullerb-react-reducer-provider
An AsyncReducerProvider example can be checked on line at gmullerb-react-reducer-provider-async codesandbox:
Edit gmullerb-react-reducer-provider-async
Examples of use can be looked at basecode-react-ts and test files.

Mappers

2 . Create the AsyncMapperProvider or SyncMapperProvider component to manage the centralized state:

Mappers

a . Define the initial state.
b . Define the mapper function.
c . Define the Mapper Provider.

SomeMapperProvider.jsx:

import React from "react";
import { SyncMapperProvider } from "react-reducer-provider";

const initialState = 0;

function map(action) {
  switch (action) {
    case "ACTION1":
      return 1;
    case "ACTION2":
      return -1;
    default:
      return 0;
  }
}

function SomeMapperProvider({ children }) {
  return (
    <SyncMapperProvider
      id="someNamedMapper"
      mapper={map}
      initialState={initialState}
    >
      {children}
    </SyncMapperProvider>
  );
}

export { SomeMapperProvider };

3 . Access the state and the dispatcher of the Provider component using the hooks or HOC provided by 'react-reducer-provider':

Dispatcher

SomeComponent1.jsx => using useMapper:

import { useMapper } from "react-reducer-provider";
import React from "react";

export default function SomeComponent1() {
  const [state, dispatch] = useMapper("someNamedMapper");
  return (
    <button onClick={() => dispatch("ACTION1")}>
      Set to 1 (from {state})!
    </button>
  );
}

SomeComponent2.jsx => using useMapperDispatcher:

import { useMapperDispatcher } from "react-reducer-provider";
import React from "react";

export default function SomeComponent2() {
  const dispatch = useMapperDispatcher("someNamedMapper");
  return <button onClick={() => dispatch("ACTION2")}>Set to -1!</button>;
}

SomeComponentN.jsx => using injectMapperState:

import { injectMapperState } from "react-reducer-provider";
import React from "react";

class SomeComponentN extends React.Component {
  render() {
    return <div>Current:{this.props.currentState}</div>;
  }
}

export default injectMapperState(SomeComponentN, 'currentState')

4 . Wrap components which will consume the SomeMapperProvider component:

SomeContainer.jsx:

import SomeComponent1 from "./SomeComponent1";
import SomeComponent2 from "./SomeComponent2";
import SomeComponentN from "./SomeComponentN";
import { SomeMapperProvider } from "./SomeMapperProvider";
import React from "react";

export default function SomeContainer() {
  return (
    <SomeMapperProvider>
      <SomeComponent1 />
      <SomeComponent2 />
      <SomeComponentN />
    </SomeMapperProvider>
  );
}

SomeContainer

An SyncMapperProvider example can be checked on line at gmullerb-react-mapper-provider codesandbox:
Edit gmullerb-react-mapper-provider
An AsyncMapperProvider example can be checked on line at gmullerb-react-mapper-provider-async codesandbox:
Edit gmullerb-react-mapper-provider-async
Examples of use can be looked at test files.

Actuators

2 . Create the ActuatorProvider component to manage a state (or whatever you need, not only state):

Actuators

a . Define actuator function.
b . Define Actuator Provider.
c. Wrap components which will consume the ActuatorProvider:

SomeContainer.jsx:

import SomeComponent1 from './path/to/SomeComponent1'
import SomeComponent2 from './path/to/SomeComponent2'
import { ActuatorProvider } from 'react-reducer-provider'
import React from 'react'

export function SomeContainer() {
  const [state, setState] = React.useState(0)
  const actuate = delta => setState(state + delta)
  return (
    <div>
      <ActuatorProvider actuator={actuate}>
        <SomeComponent1/>
        <SomeComponent2/>
      </ActuatorProvider>
      <div>
        Current:{state}
      </div>
    </div>
  )
}

3 . Access dispatcher of the Provider component using the hooks or HOC provided by 'react-reducer-provider':

Dispatcher

SomeComponent1.jsx => using useActuator:

import { useActuator } from 'react-reducer-provider'
import React from 'react'

export function SomeComponent1() {
  const dispatch = useActuator()
  return (
    <button onClick={() => dispatch(+1)}>
      Go up!
    </button>
  )
}

SomeComponent2.jsx => using injectActuator:

import { injectActuator } from "react-reducer-provider";
import React from "react";

class SomeComponent2 extends React.Component {
  render() {
    return (
      <button
        onClick={() => {
          const newState = this.props.dispatch(-1);
          console.info(newState);
        }}
      >
        Go down!
      </button>
    );
  }
}

export default injectActuator(SomeComponent2, "dispatch");

SomeContainer

This ActuatorProvider example can be checked on line at gmullerb-react-actuator-provider codesandbox:
Edit gmullerb-react-reducer-provider
Examples of use can be looked at test files.


Goal

With the introduction of React Hooks, in some way using Flux library[1] was deprecated, react-reducer-provider looks to give a quick and easy alternative using hooks to implement Flux with reducers.

[1] Not the Flux architecture.
[2] react-redux makes it too complicated.
[3] Check and Compare with other solutions at bundlephobia.com.
react-reducer-provider is the evolution of react-named-reducer (which is a derivation of react-reducer-context).


You define:

Reducers

or

Mappers

or

Actuators


and then you use them through a:

Dispatcher


Prerequisites

At least ["react": ">=16.0.0"] - React Context => when using HOC, i.e. injectReducer · injectReducerState · injectReducerDispatcher · injectMapper · injectMapperState · injectMapperDispatcher or injectTaggedAny · injectTaggedReducer · injectTaggedReducerState · injectTaggedReducerDispatcher · injectTaggedMapper · injectTaggedMapperState · injectTaggedMapperDispatcher.

["react": ">=16.8.0"] - React Hooks => when using hooks, i.e. useReducer · useReducerState · useReducerDispatcher · useMapper · useMapperState · useMapperDispatcher or useTaggedAny · useTaggedReducer · useTaggedReducerState · useTaggedReducerDispatcher · useTaggedMapper · useTaggedMapperState · useTaggedMapperDispatcher.

react-reducer-provider only enforces "react": ">=16.0.0" in package.json is up to you to be set which version you need.


Documentation

Contributing

License

MIT License


Remember

  • Use code style verification tools => Encourages Best Practices, Efficiency, Readability and Learnability.
  • Code Review everything => Encourages Functional suitability, Performance Efficiency and Teamwork.
  • If viable, Start testing early => Encourages Reliability and Maintainability.

Additional words

Don’t forget:

  • Love what you do.
  • Learn everyday.
  • Learn yourself.
  • Share your knowledge.
  • Think different!.
  • Learn from the past, dream on the future, live and enjoy the present to the max!.
  • Enjoy and Value the Quest (It’s where you learn and grow).

At life:

  • Let’s act, not complain.
  • Be flexible.

At work:

  • Let’s give solutions, not questions.
  • Aim to simplicity not intellectualism.