{"id":13481467,"url":"https://github.com/anish000kumar/redux-box","last_synced_at":"2025-05-16T06:00:25.664Z","repository":{"id":28261454,"uuid":"116676440","full_name":"anish000kumar/redux-box","owner":"anish000kumar","description":"Modular and easy-to-grasp redux  based state management, with least boilerplate","archived":false,"fork":false,"pushed_at":"2023-11-28T05:18:48.000Z","size":6415,"stargazers_count":707,"open_issues_count":13,"forks_count":21,"subscribers_count":19,"default_branch":"master","last_synced_at":"2025-05-06T06:33:03.950Z","etag":null,"topics":["react","redux","redux-saga"],"latest_commit_sha":null,"homepage":"","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/anish000kumar.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":"anish000kumar","otechie":null,"custom":null}},"created_at":"2018-01-08T12:54:24.000Z","updated_at":"2025-04-24T01:50:13.000Z","dependencies_parsed_at":"2023-09-26T05:06:43.919Z","dependency_job_id":"f96e6a81-68a1-4bb0-a6f5-74bdd162d26e","html_url":"https://github.com/anish000kumar/redux-box","commit_stats":{"total_commits":216,"total_committers":7,"mean_commits":"30.857142857142858","dds":0.09259259259259256,"last_synced_commit":"72fc5215d19b29f1ecf0c997425d5270cd1baac0"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anish000kumar%2Fredux-box","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anish000kumar%2Fredux-box/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anish000kumar%2Fredux-box/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anish000kumar%2Fredux-box/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anish000kumar","download_url":"https://codeload.github.com/anish000kumar/redux-box/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254260391,"owners_count":22041027,"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":["react","redux","redux-saga"],"created_at":"2024-07-31T17:00:52.057Z","updated_at":"2025-05-16T06:00:25.633Z","avatar_url":"https://github.com/anish000kumar.png","language":"JavaScript","funding_links":["https://issuehunt.io/r/anish000kumar"],"categories":["JavaScript","数据流","List","redux 扩展","Components","Marks"],"sub_categories":["redux 扩展","Data","[React - A JavaScript library for building user interfaces](http://facebook.github.io/react)"],"readme":"\u003cp align=\"center\"\u003e\u003ca href=\"#\" target=\"_blank\"\u003e\n\t\u003cimg style=\"max-width:700px\" src=\"https://image.ibb.co/e4Nce6/redux_box.png\" alt=\"redux_box\" border=\"0\"\u003e\n\u003c/a\u003e\u003c/p\u003e\n\n# Redux Box 2\n[![Build Status](https://travis-ci.org/anish000kumar/redux-box.svg?branch=master)](https://travis-ci.org/anish000kumar/redux-box)\n![Coveralls github](https://img.shields.io/coveralls/github/anish000kumar/redux-box)\n![GitHub](https://img.shields.io/github/license/anish000kumar/redux-box)\n![GitHub last commit](https://img.shields.io/github/last-commit/anish000kumar/redux-box)\n\n**Note: If migrating from version 1.x.x to 2, you would find breaking changes.**\n\n Redux-Box aims at abstracting away the complexity in using redux with redux-saga, while letting you manage application state in modular fashion, without losing the flexibility or without introducing new bizarre terms.\n It organizes your store as collection of **independent** modules which can be used across different  stores/applications/platforms.\n\n\u003cp align=\"center\"\u003e\u003ca href=\"https://www.youtube.com/watch?v=z3cp6xs2HmE\" target=\"_blank\"\u003e\n\t\u003cimg style=\"max-width:700px\" src=\"https://image.ibb.co/fToGkx/redux_box_1.png\" alt=\"redux_box\" border=\"0\"\u003e\n\u003c/a\u003e\u003c/p\u003e\n\u003cp align=\"center\"\u003eIllustration by \u003ca href=\"https://dribbble.com/Vraj247\"\u003eVikas\u003c/a\u003e\u003c/p\u003e\n\n## Table of contents:\n- [Redux Box 2](#redux-box-2)\n  - [Table of contents:](#table-of-contents)\n  - [What's it for:](#whats-it-for)\n  - [Installation](#installation)\n      - [Note for React Native:](#note-for-react-native)\n  - [The Basics](#the-basics)\n  - [Usage](#usage)\n    - [step 1: create a module](#step-1-create-a-module)\n    - [step 2 : register the module in redux store](#step-2--register-the-module-in-redux-store)\n    - [step 3: Use the module in component](#step-3-use-the-module-in-component)\n      - [through decorator](#through-decorator)\n  - [Live Examples (For ReduxBox@1.x.x only)](#live-examples-for-reduxbox1xx-only)\n  - [Upcoming Features](#upcoming-features)\n  - [FAQs](#faqs)\n\n\n\n## What's it for:\n\n1. **Clean, expressive and minimal reducers:**\n   If you prefer keeping your code expressive, you will feel right at home with redux-box. Have a look at a simple reducer written with and without redux-box:\n\n\u003cp align=\"center\"\u003e\u003ca href=\"https://image.ibb.co/dwP1UR/comparison.jpg\" target=\"_blank\"\u003e\n\t\u003cimg style=\"max-width:100%\" src=\"https://image.ibb.co/dwP1UR/comparison.jpg\" alt=\"redux_box\" border=\"0\"\u003e\n\u003c/a\u003e\u003c/p\u003e\n\nIf you are concerned about the state getting mutated directly in the snippet above, then you need not be. Because the `state` being passed to a mutation is **NOT** the actual `state object` of application, instead it's a [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) of the state. Redux-box relies on wonderful [immer](https://github.com/mweststrate/immer) library to achieve the expressiveness you see above.\n\n2. **Organise your giant state into modules**\n3. **Setup redux+redux-saga for our react/react-native app in a trice**\n4. **Simplified Sagas**\n5. **Just import and use store**:\n   You wouldn't need to write a dedicated HOC to interact with your store. If you need to interact with a particular store-module, you can simply import it and use it. As simple as that! Redux box offers two ways of using a module in your component : using `@connectStore` decorator or using `render props`. (refer to the usage section for better reference)\n\n## Installation\n\n```\nnpm install --save redux-box \n```\n\nOR\n\n```\nyarn add redux-box \n```\n\n\n#### Note for React Native:\nTo support the latest decorator and generator syntax, you would want to use the `.babelrc` file as below:\n```\n{\n  \"presets\": [\n    \"babel-preset-react-native-stage-0/decorator-support\"\n  ],\n  \"env\": {\n    \"development\": {\n      \"plugins\": [\n        \"transform-react-jsx-source\",\n        \"transform-es2015-typeof-symbol\"\n      ]\n    },\n    \"production\": {\n      \"plugins\": [\"transform-remove-console\"]\n    }\n  }\n}\n```\n\n\n\n## The Basics\n\nRedux box emphasizes on dividing the whole application into multiple modules. Each of these modules manages it's state seperately, with the help of 5 segments (You can skip the segments you don't need in your project):\n\n1. state\n   (It specifies the initial state of the module)\n\n2. mutations\n   (It specifies the function to be run when a specific action is dispatched, it's same as reducer but clutter-free)\n\n3. dispatchers\n   (it contains the actionCreators for your store. Each method of this object must return an action object )\n\n4. sagas\n   (this is where you write all your sagas / async operations)\n\n5. selectors\n   ( selectors can be thought of as getters or computed properties from your state)\n\n## Usage\n\n### step 1: create a module\n\nMake sure you specify a unique name for each module ('user' in this example)\n\n```javascript\n// store/user.js\nimport { createSagas, createContainer, createModule } from \"redux-box\";\nimport { call } from \"redux-saga/effects\";\n\n// define initial state\nconst state = {\n  name: \"John\",\n  email: \"john@doe.com\",\n  todos: [{ name: \"First\", type: 1 }, { name: \"Second\", type: 0 }]\n};\n\n// define dispatchers\nexport const dispatchers = {\n  setName: name =\u003e ({ type: \"SET_NAME\", name }),\n  setEmail: email =\u003e ({ type: \"SET_EMAIL\", email })\n};\n\n// define mutations\nconst mutations = {\n  SET_NAME: (state, action) =\u003e (state.name = action.name),\n  SET_EMAIL: (state, action) =\u003e (state.email = action.email)\n};\n\n// define sagas\nconst sagas = createSagas({\n  SET_EMAIL: function*(action) {\n    const response = yield call(api.updateEmail, action.email);\n  }\n});\n\n// selectors\nexport const getTodos = (state) =\u003e state.todos\nexport const getCompletedTodos = createSelector( getTodos, (todos) =\u003e {\n    return  todos.filter(todo =\u003e todo.type==1)\n})\nconst selectors = {\n    getTodos,\n    getCompletedTodos\n};\n\nexport default createModule({\n  state,\n  mutations,\n  sagas,\n});\n```\n\n### step 2 : register the module in redux store\n\n```javascript\nimport { createStore } from \"redux-box\";\nimport userModule  from \"./user\";\n\nexport default createStore({\n  user: userModule\n});\n```\n\nOPTIONAL: if you need to create store with some reducers and middlewares, the signature of createStore method from redux-box goes like this:(if you have already included a module in modules array, you need **NOT** to register it's sagas or reducers manually by including in config object)\n\n```javascript\ncreateStore((modules: Object), (config: Object));\n\n//example config object\nconfig = {\n\n  //define redux middlewares\n  middlewares: [],\n  \n   //define the default state for your store\n  preloadedState: {},\n\n  // sagas to be manually registered\n  sagas: [userModule.sagas, testModule.sagas],\n\n  // reducers to be manually registered\n  reducers: {\n    user: yourCustomReducer\n  },\n  decorateReducer: reducer =\u003e {\n    //do something\n    return newReducer;\n  },\n  \n  //overrite the compose function\n  composeRedux: (composer) =\u003e {\n    // do something\n    // return modified compose function\n  },\n  \n  // Dynamically decide when to enable or disable dev-tools \n  enableDevTools: () =\u003e true,\n  devToolOptions: {}\n};\n```\n\nAfter this you would need to wrap your root component around the Provider tag like so :\n\n```javascript\nimport React from \"react\";\nimport { Provider } from \"react-redux\";\nimport store from \"./store\";\nimport RootComponent from \"./components/RootComponent\";\n\nclass App extends React.component {\n  render() {\n    return (\n      \u003cProvider store={store}\u003e\n        \u003cRootComponent /\u003e\n      \u003c/Provider\u003e\n    );\n  }\n}\n\nexport default App;\n```\n\n### step 3: Use the module in component\n\n#### through decorator\n\n```javascript\nimport React, { Component } from \"react\";\nimport { connectStore } from \"redux-box\";\nimport { getTodos, getCompletedTodos, dispatchers } from \"./user\";\n\n@connectStore({\n  mapState: state =\u003e ({\n    user: state.user\n  }), \n\n  mapSelectors: {\n    todos: getTodos,\n    completedTodos: getCompletedTodos\n  }, \n\n  mapDispatchers: {\n    setName: dispatchers.setName,\n    setEmail: dispatchers.setEmail\n  }\n})\nexport default class AppComponent extends Component {\n  componentDidMount() {\n    console.log(this.props.user);\n    /*\n\t{\n\t    name : 'John',\n\t    email : 'john@doe.com',\n\t    getTodos: [{ name: \"First\", type: 1 }, { name: \"Second\", type: 0 }],\n\t    getCompletedTodos: [{ name: \"First\", type: 1 }],\n\t    setName : fn(arg),\n\t    setEmail : fn(arg)\n\t}\n    */\n  }\n\n  render() {\n    const { user } = this.props;\n    return (\n      \u003cdiv\u003e\n        \u003ch1\u003e{user.name}\u003c/h1\u003e\n        \u003ch2\u003e{user.email}\u003c/h2\u003e\n\t\n\t\u003cbutton onClick={()=\u003e{ \n\t  this.props.setName('jane doe')\n\t}}\u003e Change Name \u003c/button\u003e\n\t\n      \u003c/div\u003e\n    );\n  }\n}\n```\n\n## Live Examples (For ReduxBox@1.x.x only)\n**Docs for V2 are in progress, would be updated in a few days**\n\nHere are some examples to let you play around with redux-box\n\n1. Basic example - https://stackblitz.com/edit/react-3c8vsn?file=Hello.js\n2. Example showing redux-saga usage: - https://stackblitz.com/edit/react-qmedt4?file=Hello.js\n3. Example usage with redux-form: https://stackblitz.com/edit/react-w4dqth?file=store%2Findex.js\n4. Example usage with redux-persist : https://stackblitz.com/edit/react-pezrbb?file=store%2Findex.js\n5. Example showing usage of preloaded state for SSR:  https://stackblitz.com/edit/react-qcasn4?file=store/index.js\n6. Using redux-observable: https://stackblitz.com/edit/react-zu8qjn?file=store%2Fuser%2Fepics.js\n\n## Upcoming Features\n*No pending feature requests*\n\u003e *[Suggest a new feature here](https://github.com/anish000kumar/redux-box/labels/feature)*\n\n## FAQs\n1. **Error:** \n```\nEither wrap the root component in a \u003cProvider\u003e, or explicitly pass “store” as a prop to \"Connect(MyComponent)\n```\n  This error occurs because of mismatch among versions of dependencies of redux-box, most likely `react-redux`. You can run this  \tcommand to fix this issue for now:\n```  \n  yarn add react-redux@5.0 \n```\n1. **Decorators aren't working**\n\nDecorators aren't still a part of es6. To use the decorator syntax you should be using a transpiler like babel. Also, in create-react-app projects the `.babelrc` file doesn't really work so you would need to run `npm run eject` to be able to use custom babel-plugins. Following `.babelrc` should suffice:\n```javascript\n{\n  \"plugins\": [\"transform-decorators-legacy\", \"styled-components\"],\n  \"presets\": [ \"react\",\"es2015\", \"stage-2\" ]\n}\n```\n\nIn case you wouldn't like to eject, you can still use redux-box without decorators. Like so:\n\n```javascript\n\n@connectStore({\n ui: uiModule\n})\nclass TestComponent extends React.Component{\n  ...\n}\nexport default TestComponent\n\n```\n\nAbove snippet is equivalent to:\n\n```javascript\n\nclass TestComponent extends React.Component{\n  ...\n}\n\nexport default connectStore({\n ui: uiModule\n})(TestComponent)\n\n```\n\n2. **Can I use all the features of redux-box, with `createStore` from redux instead?**\n\nYes, you can! Here's the script showing how you can use `createStore` from redux, to setup your modules (with reducers, sagas and middlewares):\n(v1.3.9 onwards)\n\n```javascript\nimport { applyMiddleware, combineReducers, compose, createStore } from \"redux\";\nimport createSagaMiddleware from \"redux-saga\";\nimport { all } from \"redux-saga/effects\";\nimport { moduleToReducer } from \"redux-box\";\nimport { module as homeModule } from \"./home\";\nimport { module as userModule } from \"./user\";\n\n//hook up your module reducers\nconst combinedReducer = combineReducers({\n  home: moduleToReducer(homeModule),\n  user: moduleToReducer(userModule)\n});\n\n// hook up your module sagas\nconst sagas = [...homeModule.sagas, ...userModule.sagas];\n\n// hook up your middlewares here\nconst sagaMiddleware = createSagaMiddleware();\nconst middlewares = [sagaMiddleware];\n\n//what follows below is the usual approach of setting up store\nconst composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;\nlet enhancer = composeEnhancers(applyMiddleware(...middlewares));\n\nfunction* rootSaga() {\n  yield all(sagas);\n}\n\nconst store = createStore(combinedReducer, enhancer);\nsagaMiddleware.run(rootSaga);\nexport default store;\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanish000kumar%2Fredux-box","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanish000kumar%2Fredux-box","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanish000kumar%2Fredux-box/lists"}