{"id":15070005,"url":"https://github.com/gmullerb/react-reducer-context","last_synced_at":"2026-01-03T21:10:36.781Z","repository":{"id":38455561,"uuid":"209610411","full_name":"gmullerb/react-reducer-context","owner":"gmullerb","description":"React Component to manage State through reducers using contexts and hooks.","archived":false,"fork":false,"pushed_at":"2023-01-07T09:53:10.000Z","size":1711,"stargazers_count":0,"open_issues_count":25,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-19T17:05:58.686Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gmullerb.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-09-19T17:21:50.000Z","updated_at":"2019-12-19T16:13:45.000Z","dependencies_parsed_at":"2023-02-06T20:30:37.234Z","dependency_job_id":null,"html_url":"https://github.com/gmullerb/react-reducer-context","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmullerb%2Freact-reducer-context","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmullerb%2Freact-reducer-context/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmullerb%2Freact-reducer-context/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmullerb%2Freact-reducer-context/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gmullerb","download_url":"https://codeload.github.com/gmullerb/react-reducer-context/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243838042,"owners_count":20355974,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-25T01:46:25.210Z","updated_at":"2026-01-03T21:10:36.736Z","avatar_url":"https://github.com/gmullerb.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://assets.gitlab-static.net/uploads/-/system/project/avatar/14399495/react.reducer.context.png\"/\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eReact Component to manage State through reducers using contexts and hooks\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003ewith typings for Typescript and Flow\u003c/p\u003e\n\n__________________\n\n[![license](https://img.shields.io/github/license/mashape/apistatus.svg)](LICENSE.txt) ![GitHub package.json version](https://img.shields.io/github/package-json/v/gmullerb/react-reducer-context.svg?logo=npm) ![coverage](https://gitlab.com/gmullerb/react-reducer-context/badges/master/coverage.svg) [![react-reducer-context](https://img.shields.io/badge/npm-react--reducer--context-blue?logo=npm)](https://www.npmjs.com/package/react-reducer-context)\n\nThis project is licensed under the terms of the [MIT license](LICENSE.txt).\n__________________\n\n## Quick Start\n\n1 . Add dependency:\n\n`package.json`:\n\n```json\n  ..\n  \"dependencies\": {\n    \"react\": \"^16.8.0\"\n    \"react-reducer-context\": \"1.0.2\",\n    ..\n```\n\n2 . Create the **`ReducerContext`** component to manage state:\n\n* Define the initial state.\n* Define the reducer function.\n* Define the `ReducerContext`.\n\n**`SomeReducerContext.jsx`**:\n\n```jsx\nimport React, { createContext } from 'react'\nimport ReducerContext from 'react-reducer-context'\n\nconst initialState = 0\n\nfunction reduce(prevState, action) {\n  switch (action) {\n    case 'ACTION1':\n      return prevState + 1\n    case 'ACTION2':\n      return prevState - 1\n    default:\n      return prevState\n  }\n}\n\nconst someReducerContext = createContext(null)\n\nfunction SomeReducerContext({ children }) {\n  return (\n    \u003cReducerContext\n      context={someReducerContext}\n      reducer={reduce}\n      initialState={initialState}\n    \u003e\n      {children}\n    \u003c/ReducerContext\u003e\n  )\n}\n\nexport {\n  someReducerContext as default,\n  SomeReducerContext\n}\n```\n\n3 . Wrap components which needs the `ReducerContext` component:\n\n`SomeContainer.jsx`:\n\n```jsx\nimport SomeComponent1 from './path/to/SomeComponent1'\nimport SomeComponent2 from './path/to/SomeComponent2'\nimport SomeComponentN from './path/to/SomeComponentN'\nimport { SomeReducerContext } from '../path/to/SomeReducerContext'\nimport React from 'react'\n\nexport default function SomeContainer() {\n  return (\n    \u003cSomeReducerContext\u003e\n      \u003cSomeComponent1/\u003e\n      \u003cSomeComponent2/\u003e\n      \u003cSomeComponentN/\u003e\n    \u003c/SomeReducerContext\u003e\n  )\n}\n```\n\n4 . Access the `ReducerContext` component using `'react-reducer-context'` hooks:\n\n* **`useReducerContext`**.\n* **`useReducerDispatcher`**.\n* **`useReducerState`**.\n\n`SomeComponent1.jsx` [1]:\n\n```jsx\nimport someReducerContext from '../path/to/SomeReducerContext'\nimport { useReducerContext } from 'react-reducer-context'\nimport React from 'react'\n\nexport default function SomeComponent1() {\n  const { state, dispatch } = useReducerContext(someReducerContext)\n  return (\n    \u003cbutton onClick={() =\u003e dispatch('ACTION1')}\u003e\n      Go up (from {state})!\n    \u003c/button\u003e\n  )\n}\n```\n\n`SomeComponent2.jsx` [1]:\n\n```jsx\nimport someReducerContext from '../path/to/SomeReducerContext'\nimport { useReducerDispatcher } from 'react-reducer-context'\nimport React from 'react'\n\nexport default function SomeComponent2() {\n  const dispatch = useReducerDispatcher(someReducerContext)\n  return (\n    \u003cbutton onClick={() =\u003e dispatch('ACTION2')}\u003e\n      Go down!\n    \u003c/button\u003e\n  )\n}\n```\n\n`SomeComponentN.jsx` [1]:\n\n```jsx\nimport someReducerContext from '../path/to/SomeReducerContext'\nimport { useReducerState } from 'react-reducer-context'\nimport React from 'react'\n\nexport default function SomeComponentN() {\n  const currentState = useReducerState(someReducerContext)\n  return (\n    \u003cdiv\u003e\n      Current:{currentState}\n    \u003c/div\u003e\n  )\n}\n```\n\n\u003e This example can be checked on line: live at [gmullerb-react-reducer-context demo](https://57esd.csb.app/) and the code is at [gmullerb-react-reducer-context codesandbox](https://codesandbox.io/s/gmullerb-react-reducer-context-57esd?module=%2Fsrc%2FSomeReducerContext.jsx):  \n[![Edit gmullerb-react-reducer-context](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/gmullerb-react-reducer-context-57esd?module=%2Fsrc%2FSomeReducerContext.jsx)  \n\u003e [1] Injection can be used in order to improve design, but in favor of quick example this was surrender, look at [Injection](readme/with-injection.md) for injection example.  \n\n3 . Jump based on requirements into:  \n\n* [`ReducerContext` | `useReducerContext` | `useReducerState` | `useReducerDispatcher`](#reference).\n  * [Nesting](#nesting).\n  * [Typings](#typings).\n  * [Prerequisites](#prerequisites).\n  * Extras:\n    * [With Injection](readme/with-injection.md).\n      * [with Flow typings](readme/with-injection-and-flow-typings.md).\n      * [with Typescript typings](readme/with-injection-and-ts-typings.md).\n    * [With Actions Creators](readme/with-actions-creators.md)\n      * [with Flow typings](readme/with-actions-creators-and-flow-typings.md)\n      * [with Typescript typings](readme/with-actions-creators-and-ts-typings.md)\n* [Extending/Developing](readme/developing.md)\n* [MIT License](LICENSE.txt)\n\n__________________\n\n## Goal\n\nWith the introduction of React Hooks, in some way using Flux library[1] was deprecated, react-reducer-context looks to **give a quick and easy alternative using hooks to implement Flux with reducers**, with typings for Typescript and Flow.\n\n\u003e [1] Not the Flux architecture.\n__________________\n\n## `ReducerContext` | `useReducerContext` | `useReducerState` | `useReducerDispatcher`\n\n[`ReducerContext`](src/main/js/ReducerContext.js) is a React Component which defines a [React Context](https://reactjs.org/docs/context.html) that allows to Manage State using [Flux](http://facebook.github.io/flux), an application architecture that handles application states in a unidirectional way.\n\n* Flux is composed basically with:\n  * Stores: keeps states of the app (or components).\n    * Reducer: function that changes the State based on an Action and the previous State.\n  * Actions: triggers changes in Store.\n  * Dispatcher: sends Actions to the Store.\n    * Mainly the bridge between the Store and Components.\n\n![Flux architecture](readme/flux.svg \"Flux architecture\")\n\n[`ReducerContext`](src/main/js/ReducerContext.js) is a React \"Special\" Element that requires 3 properties:\n\n* `context`: constitutes the [React Context](https://reactjs.org/docs/context.html) which will be handle by this component.\n  * use `React.createContext(null)` to create the context.\n* `reducer`: a function that will receive the current state and an action to produce a new state.\n  * internally use [`useReducer` hook](https://reactjs.org/docs/hooks-reference.html#usereducer), which return the current state and a [dispatcher](http://facebook.github.io/flux/docs/dispatcher).\n* `initialState`: inception state for the component.\n\n```jsx\n  \u003cReducerContext\n    context={someReducerContext}\n    reducer={reduce}\n    initialState={initialState}\n  \u003e\n    {children}\n  \u003c/ReducerContext\u003e\n```\n\nEach `ReducerContext` is equivalent to an Flux stream:\n\n![ReducerContext](readme/react-reducer-context.svg \"ReducerContext\")\n\n`children` elements will be **able to access the State and Dispatcher**.  \nThere are different ways of doing this:\n\nA . Using `useReducerContext`:\n\n* `useReducerContext` is a \"typings-friendly\" version of `useContext` that returns the status and dispatcher.\n  * which also increase Readability.\n\n```jsx\n  const { state, dispatch } = useReducerContext(someReducerContext)\n```\n\ne.g.:\n\n```jsx\nimport someReducerContext from '../path/to/SomeReducerContext'\nimport { useReducerContext } from 'react-reducer-context'\nimport React from 'react'\n\nexport default function SomeComponent() {\n  const { state, dispatch } = useReducerContext(someReducerContext)\n  return (\n    \u003cbutton onClick={() =\u003e dispatch({\n        type: 'SOME_ACTION',\n        data: someValue\n      })}\n    \u003e\n      Do something! ({state.someValue})\n    \u003c/button\u003e\n  )\n}\n```\n\nB . Using `useReducerState`:\n\n* `useReducerState` is a \"typings-friendly\" function that allows to access only state.\n  * which also increase Readability.\n\n```jsx\n  const state = useReducerState(someReducerContext)\n```\n\ne.g.:\n\n```jsx\nimport someReducerContext from '../path/to/SomeReducerContext'\nimport { useReducerState } from 'react-reducer-context'\nimport React from 'react'\n\nexport default function SomeComponent() {\n  const state = useReducerState(someReducerContext)\n  return (\n    \u003cdiv\u003e\n      Some Value: ({state.someValue})\n    \u003c/div\u003e\n  )\n}\n```\n\nC . Using `useReducerDispatcher`:\n\n* `useReducerDispatcher` is a \"typings-friendly\" function that allows to access only the dispatcher.\n  * which also increase Readability.\n\n```jsx\n  const dispatch = useReducerDispatcher(someReducerContext)\n```\n\ne.g.:\n\n```jsx\nimport someReducerContext from '../path/to/SomeReducerContext'\nimport { useReducerDispatcher } from 'react-reducer-context'\nimport React from 'react'\n\nexport default function SomeComponent() {\n  const dispatch = useReducerDispatcher(someReducerContext)\n  return (\n    \u003cbutton onClick={() =\u003e dispatch({\n        type: 'SOME_ACTION',\n        data: someValue\n      })}\n    \u003e\n      Do something!\n    \u003c/button\u003e\n  )\n}\n```\n\nD . Using \"old\" traditional [`useContext`](https://reactjs.org/docs/hooks-reference.html#usecontext):\n\n```jsx\n  const [state, dispatch] = useContext(someReducerContext)\n```\n\ne.g.:\n\n```jsx\nimport someReducerContext from '../path/to/SomeReducerContext'\nimport React, { useContext } from 'react'\n\nexport default function SomeComponent() {\n  const [state, dispatch] = useContext(someReducerContext)\n  return (\n    \u003cbutton onClick={() =\u003e dispatch({\n        type: 'SOME_ACTION',\n        data: someValue\n      })}\n    \u003e\n      Do something! ({state.someValue})\n    \u003c/button\u003e\n  )\n}\n```\n\nE . Using [`Context.Consumer`](https://reactjs.org/docs/context.html#contextconsumer):\n\n```jsx\n  \u003csomeReducerContext.Consumer\u003e\n    {\n      ([state, dispatch]) =\u003e (\n        ..\n      )\n    }\n  \u003c/someReducerContext.Consumer\u003e\n```\n\ne.g.:\n\n```jsx\nimport someReducerContext from '../path/to/SomeReducerContext'\nimport React, { useContext } from 'react'\n\nexport default function SomeComponent() {\n  return (\n    \u003csomeReducerContext.Consumer\u003e\n    {\n      ([state, dispatch]) =\u003e (\n        \u003cbutton onClick={() =\u003e dispatch({\n            type: 'SOME_ACTION',\n            data: someValue\n          })}\n        \u003e\n          Do something! ({state.someValue})\n        \u003c/button\u003e\n      )\n    }\n    \u003c/someReducerContext.Consumer\u003e\n  )\n}\n```\n\n\u003e There is another way using [`contextType`](https://reactjs.org/docs/context.html#classcontexttype), but is not functional approach, so it is not exposed.  \n\n### Nesting\n\nBased on [React Context](https://reactjs.org/docs/context.html), `ReducerContext` can be nested in layers, in order to have several nested Reducer/State.\n\n```jsx\n  \u003cReducerContext\n    context={someReducerContext1}\n    reducer={reduce1}\n    initialState={initialState1}\n  \u003e\n    {someChildren}\n    \u003cReducerContext\n      context={someReducerContextN}\n      reducer={reduceN}\n      initialState={initialStateN}\n    \u003e\n      {moreChildren}\n    \u003c/ReducerContext\u003e\n  \u003c/ReducerContext\u003e\n```\n\n`moreChildren` can access the State and the Dispatcher of the ReducerContext1 plus the State and the Dispatcher of the ReducerContextN.\n\n![Nested ReducerContext](readme/nested-reducer-context.svg \"Nested ReducerContext\")\n\n### Typings\n\n**`react-reducer-context` defines typings for Flow and Typescript**:\n\n* Any can be used without an \"special\" [1] configuration.\n  * Typings definitions are located together with source files:\n    * Flow: [`ReducerContext.js.flow`](src/main/js/ReducerContext.js.flow).\n    * Typescript: [`ReducerContext.d.ts`](src/main/js/ReducerContext.d.ts).\n\nBoth provide the following types:\n\n* `ReducerContext\u003cSTATE, ACTION\u003e`: specifies the Function React Component structure.\n* `ReducerContextProps\u003cSTATE, ACTION\u003e`: defines the properties receive the `ReducerContext`.\n* `ReducerContextDefaultValue\u003cSTATE, ACTION\u003e`: specifies the type of the `React.Context` when created.\n  * Essentially is a `ReducerContextValue\u003cSTATE, ACTION\u003e` which also allows a `null` value, which is required when creating the context.\n  * If required, this type should be use only when creating the `ReducerContext`.\n* `ReducerContextValue\u003cSTATE, ACTION\u003e`: defines the type of the value contained in the `React.Context`.\n  * This type should be for using the created `ReducerContext` (that never going to be null).\n* `ReducerContextInterface\u003cSTATE, ACTION\u003e`: defines the type of the value return by `useReducerContext`.\n* `Dispatcher\u003cACTION\u003e`: defines the function that receives the action that triggers the change of the state.\n\n`STATE`: State type.  \n`ACTION`: Action type.  \n\nE.G.:\n\n`SomeReducerContext.jsx` or `SomeReducerContext.tsx`:\n\n```jsx\n..\n\nconst initialState: number = 0\n\nfunction reduce(prevState: number, action: string): number {\n  switch (action) {\n    case 'ACTION1':\n      return prevState + 1\n    case 'ACTION2':\n      return prevState - 1\n    default:\n      return prevState\n  }\n}\n\nconst someReducerContext: Context\u003cReducerContextDefaultValue\u003cnumber, string\u003e\u003e = createContext(null)\n\n..\n\n```\n\n`SomeComponent.jsx` or `SomeComponent.tsx`:\n\n```jsx\n  ..\n  const { state, dispatch }: ReducerContextInterface\u003cnumber, string\u003e = useReducerContext(someReducerContext)\n  ..\n```\n\nor\n\n```jsx\n  ..\n  const dispatch: Dispatcher\u003cstring\u003e = useReducerDispatcher(someReducerContext)\n  ..\n```\n\nor\n\n```jsx\n  ..\n  const state: number = useReducerState(someReducerContext)\n  ..\n```\n\n* A more \"complete\" example with Flow can be seen at: [`typingTest.jsx`](src/test/typings/flow/typingTest.jsx).\n* A more \"complete\" example with Typescript can be seen at: [`typingTest.tsx`](src/test/typings/ts/typingTest.tsx).\n\n\u003e Initial example with Flow typings can be checked on line: live at [gmullerb-react-reducer-context-flow demo](https://7ubs7.csb.app/) and the code is at [gmullerb-react-reducer-context-flow codesandbox](https://codesandbox.io/s/gmullerb-react-reducer-context-flow-7ubs7?module=%2Fsrc%2FSomeReducerContext.jsx):  \n[![Edit gmullerb-react-reducer-context](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/gmullerb-react-reducer-context-flow-7ubs7?module=%2Fsrc%2FSomeReducerContext.jsx)  \n\u003e Initial example with Typescript typings can be checked on line: live at [gmullerb-react-reducer-context-ts demo](https://kwqir.csb.app/) and the code is at [gmullerb-react-reducer-context-ts codesandbox](https://codesandbox.io/s/gmullerb-react-reducer-context-ts-kwqir?module=%2Fsrc%2FSomeReducerContext.tsx):  \n[![Edit gmullerb-react-reducer-context-ts](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/gmullerb-react-reducer-context-ts-kwqir?module=%2Fsrc%2FSomeReducerContext.tsx)  \n\u003e [1] Only the usual Flow or Typescript configuration (e.g. no need for @types).\n\n__________________\n\n### Prerequisites\n\n* [React Hooks](https://reactjs.org/docs/hooks-overview.html) =\u003e [`\"react\": \"^16.8.0\"`](https://www.npmjs.com/package/react).\n\n__________________\n\n## Extending/Developing\n\n[Developing](readme/developing.md)\n\n## Documentation\n\n* [`CHANGELOG.md`](CHANGELOG.md): add information of notable changes for each version here, chronologically ordered [1].\n\n\u003e [1] [Keep a Changelog](http://keepachangelog.com)\n\n## License\n\n[MIT License](LICENSE.txt)\n__________________\n\n## Remember\n\n* Use code style verification tools =\u003e Encourages Best Practices, Efficiency, Readability and Learnability.\n* Start testing early =\u003e Encourages Reliability and Maintainability.\n* Code Review everything =\u003e Encourages Functional suitability, Performance Efficiency and Teamwork.\n\n## Additional words\n\nDon't forget:\n\n* **Love what you do**.\n* **Learn everyday**.\n* **Learn yourself**.\n* **Share your knowledge**.\n* **Learn from the past, dream on the future, live and enjoy the present to the max!**.\n\nAt life:\n\n* Let's act, not complain.\n* Be flexible.\n\nAt work:\n\n* Let's give solutions, not questions.\n* Aim to simplicity not intellectualism.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgmullerb%2Freact-reducer-context","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgmullerb%2Freact-reducer-context","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgmullerb%2Freact-reducer-context/lists"}