{"id":24087351,"url":"https://github.com/madetheforcebewithyou/redux-knife-manager","last_synced_at":"2025-05-05T19:54:58.708Z","repository":{"id":57350919,"uuid":"116128734","full_name":"madetheforcebewithyou/redux-knife-manager","owner":"madetheforcebewithyou","description":"The lightweight and flexible library for implementing Redux entities with React.","archived":false,"fork":false,"pushed_at":"2018-08-18T03:30:31.000Z","size":211,"stargazers_count":32,"open_issues_count":2,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-12T13:56:57.067Z","etag":null,"topics":["react","redux","redux-modules","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/madetheforcebewithyou.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-01-03T11:21:57.000Z","updated_at":"2020-12-03T21:49:17.000Z","dependencies_parsed_at":"2022-09-16T21:20:40.596Z","dependency_job_id":null,"html_url":"https://github.com/madetheforcebewithyou/redux-knife-manager","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madetheforcebewithyou%2Fredux-knife-manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madetheforcebewithyou%2Fredux-knife-manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madetheforcebewithyou%2Fredux-knife-manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madetheforcebewithyou%2Fredux-knife-manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/madetheforcebewithyou","download_url":"https://codeload.github.com/madetheforcebewithyou/redux-knife-manager/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252568042,"owners_count":21769353,"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-modules","redux-saga"],"created_at":"2025-01-10T03:24:41.189Z","updated_at":"2025-05-05T19:54:58.676Z","avatar_url":"https://github.com/madetheforcebewithyou.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Redux Knife Manager\n\n[![Build Status](https://travis-ci.org/madetheforcebewithyou/redux-knife-manager.svg?branch=master)](https://travis-ci.org/madetheforcebewithyou/redux-knife-manager)\n[![Coverage Status](https://coveralls.io/repos/github/madetheforcebewithyou/redux-knife-manager/badge.svg?branch=master)](https://coveralls.io/github/madetheforcebewithyou/redux-knife-manager?branch=master)\n[![Maintainability](https://api.codeclimate.com/v1/badges/6fe830dc12447fa3922b/maintainability)](https://codeclimate.com/github/madetheforcebewithyou/redux-knife-manager/maintainability)\n[![node version](https://img.shields.io/node/v/redux-knife-manager.svg)](https://nodejs.org/download)\n[![npm version](https://badge.fury.io/js/redux-knife-manager.svg)](https://badge.fury.io/js/redux-knife-manager)\n[![npm monthly download](https://img.shields.io/npm/dm/redux-knife-manager.svg)](https://www.npmjs.com/package/redux-knife-manager)\n[![license](https://img.shields.io/github/license/madetheforcebewithyou/redux-knife-manager.svg)](https://opensource.org/licenses/MIT)\n\nRedux Knife Manager is the lightweight library for easily managing, encapsulating and generating the redux entities such as action, reducer, selector and so on.\n\nRedux Knife Manager has following features:\n* It is very suitable for [redux](https://github.com/reactjs/redux), [redux-saga](https://github.com/redux-saga/redux-saga) and related stacks.\n* Use naming convention to generate the redux action, redux action type and selector automatically.\n* Keep the codebase more cleaner even if cross-container interactions are very often.\n* Prevent the collision of action type constants.\n* Reuse the selector concept in redux containers and redux saga flows.\n* Support universal application.\n* You can focus on redux reducer implementation and testing.\n\nIn short, it can be used to reduce the codebase complexity and gain the better convention while developing.\n\n## Installation\nPlease use the following command to install Redux Knife Manager, assume you use the package management system with yarn\n\n```shell\nyarn add redux-knife-manager redux\n```\n\nor npm.\n\n```shell\nnpm install --save redux-knife-manager redux\n```\n\n## Quick start\n1. Consider the counter application, we need to configure the `counter knife` first.\n\n```javascript\nimport { createStore, combineReducers } from 'redux';\nimport reduxKnifeManager from 'redux-knife-manager';\n\n// 1. Initialize Redux Knife Manager\nreduxKnifeManager.initialize();\n\n// 2. Add a knife to Redux Knife Manager\nreduxKnifeManager.addKnife('counter', {\n  actionMap: ['increase', 'decrease'],\n  reducerMap: ({ increase, decrease }) =\u003e ({\n    [increase]: (state, action) =\u003e ({\n      num: state.num + action.value,\n    }),\n\n    [decrease]: (state, action) =\u003e ({\n      num: state.num - action.value,\n    }),\n  }),\n  defaultState: {\n    num: 0,\n  },\n});\n\n// 3. reducer can also listen cross-category actions\nreduxKnifeManager.addKnife('inverse', {\n  actionMap: ['reset'],\n  reducerMap: (\n    { reset },\n    { counter: { increase, decrease } },\n  ) =\u003e ({\n    [counter]: (state, action) =\u003e ({\n      num: state.num - action.value,\n    }),\n\n    [counter]: (state, action) =\u003e ({\n      num: state.num + action.value,\n    }),\n\n    [reset]: () =\u003e ({\n      num: 0,\n    }),\n  }),\n  defaultState: {\n    num: 0,\n  },\n});\n\n// 4. Configure the redux store\nconst store = createStore(combineReducers(reduxKnifeManager.getRootReducer()));\n```\n\n2. After configuring the `counter knife`, we can now get the counter value and dispatch the increase/decrease action.\n\n```javascript\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport { connect } from 'react-redux';\nimport reduxKnifeManager from 'redux-knife-manager';\n\n// 1. Get the counter knife\nconst counterKnife = reduxKnifeManager.getKnife('counter');\n\n// 2. Configure the mapStateToProps\nfunction mapStateToProps(state) {\n  return {\n    num: counterKnife.selector.get(state, 'num'),\n  };\n}\n\n// 3. Connect to redux\n@connect(mapStateToProps)\nexport default class App extends React.Comopnent {\n  static propTypes = {\n    dispatch: PropTypes.func,\n    num: PropTypes.number,\n  };\n\n  onIncrease() {\n    // dispatch the increase action\n    const { dispatch } = this.props;\n    dispatch(counterKnife.action.increase({ value: Math.random() }));\n  }\n\n  onDecrease() {\n    // dispatch the decrease action\n    const { dispatch } = this.props;\n    dispatch(counterKnife.action.decrease({ value: 1 }));\n  }\n\n  render() {\n    const { num } = this.props;\n\n    return (\n      \u003cdiv\u003e\n        \u003cbutton onClick={this.onIncrease}\u003eIncrease\u003c/button\u003e\n        \u003cbutton onClick={this.onDecrease}\u003eDecrease\u003c/button\u003e\n        \u003cdiv\u003e{num}\u003c/div\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n```\n\n3. The `counter knife` can be also used in other places, assume you are using `redux-saga` in asynchronous flow management.\n\n```javascript\nimport { takeEvery } from 'redux-saga/effects';\nimport reduxKnifeManager from 'redux-knife-manager';\n\nconst counterKnife = reduxKnifeManager.getKnife('counter');\n\nexport default function* counterSaga() {\n  yield takeEvery(counterKnife.actionType.increase, function* handleIncrese(action) {\n    // do something like print the action value\n    console.log(action);\n  });\n}\n```\n\n## Detailed examples\nThe project takes todoMVC as detailed examples, please refers the [examples folder](https://github.com/madetheforcebewithyou/redux-knife-manager/tree/master/examples).\n\n## API reference\n### `initialize(options)`\nThe function `initialize` is used to initialize Redux Knife Manager. Since Redux Knife Manager is the single instance, the knives and related entries will be **released** when `initialize` has been called.\n\n#### Arguments\n* **options (Object):**\n  * **namespace (String, default: 'app'):**  \n    The namespace is the prefix of top level of redux store to restore the state of knives.\n\n#### Example\n```javascript\nreduxKnifeManager.initialize({\n  namespace: 'example',\n});\n```\n\n### `addKnife(category, config)`\nThe function `addKnife` is used to add a knife to Redux Knife Manager. It will generate the redux entities such as action, reducer, selector automatically by the given `config`.\n\n#### Arguments\n* **category (String):**  \n  It is the the identifier to associate with the knife.\n* **config (Object):**  \n  * **actionMap (Array of String):**  \n    Redux Knife Manager will generate collections of action generator and action type which are based on `actionMap`.\n  * **reducerMap (Function(actionType, allActionType)):**  \n    Redux Knife Manager will pass generated actions to `reducerMap`. And it **must** return the object of definition of reducers which are associated with spicfied actions.\n  * **defaultState (Object):**  \n    The default state of knife which is associated with `category`.\n\n#### Returns\n* Return **Knife Object** if the knife is configured successfully.\n* Otherwise, **undefined**.\n\n#### Example\n```javascript\n// 1. Initialize Reudx Knife Manager\nreduxKnifeManager.initialize({\n  namespace: 'example',\n});\n\n\n// 2. Add a knife to Reudx Knife Manager\nreduxKnifeManager.addKnife('counter', {\n  actionMap: ['increase', 'decrease'],\n  reducerMap: ({ increase, decrease }) =\u003e ({\n    [increase]: (state, action) =\u003e ({\n      num: state.num + action.value,\n    }),\n\n    [decrease]: (state, action) =\u003e ({\n      num: state.num - action.value,\n    }),\n  }),\n  defaultState: {\n    num: 0,\n  },\n});\n\n// 3. reducer can also listen cross-category actions\nreduxKnifeManager.addKnife('inverse', {\n  actionMap: ['reset'],\n  reducerMap: (\n    { reset },\n    { counter: { increase, decrease } },\n  ) =\u003e ({\n    [increase]: (state, action) =\u003e ({\n      num: state.num - action.value,\n    }),\n\n    [decrease]: (state, action) =\u003e ({\n      num: state.num + action.value,\n    }),\n\n    [reset]: () =\u003e ({\n      num: 0,\n    }),\n  }),\n  defaultState: {\n    num: 0,\n  },\n});\n\n// 4. Configure the redux store\nconst store = createStore(combineReducers(reduxKnifeManager.getRootReducer()));\n\n/* 6. The redux store will be as follow:\n * {\n *   example: {\n *     counter: {\n *       num: 0,\n *     },\n *     inverse: {\n *       num: 0,\n *     },\n *  }\n */\n```\n\n\n### `getKnife(category)`\nThe function `addKnife` is used to retrieve a knife from Redux Knife Manager.\n\n#### Arguments\n* **category (String):**  \n  It is the the identifier to retrieve the knife.\n\n#### Returns\n* Return the **Knife Object** which is associated with the given `category`.\n* Otherwise, it will return **undefined** if the knife is not exist.\n* **Knife Object:**\n  * **selector (Object):**  \n    The collection of selector. It will generate the `get` method to retrieve the whole state, and selectors to retr.\n  * **actionType (Object):**  \n    The collection of action type, and the properties of actionType are based on `actionMap`.\n  * **action (Object):**  \n    The collection of action generator, and the properties of action are based on `actionMap`. In order to simplify the interface, the action generator **do only accept** the payload with the plain object, and it will construct the simple action generator. The definition of action generator is as follow:\n```javascript\n      action[name] = (payload = {}) =\u003e ({\n        type: autoGeneratedConstant,\n        ...payload,\n      });\n```\n\n#### Example\n```javascript\n// 1. Initialize Redux Knife Manager\nreduxKnifeManager.initialize({\n  namespace: 'example',\n});\n\n// 2. Add a knife to Redux Knife Manager\nreduxKnifeManager.addKnife('counter', {\n  actionMap: ['increase', 'decrease'],\n  reducerMap: ({ increase, decrease }) =\u003e ({\n    [increase]: (state, action) =\u003e ({\n      num: state.num + action.value,\n    }),\n\n    [decrease]: (state, action) =\u003e ({\n      num: state.num - action.value,\n    }),\n  }),\n  defaultState: {\n    num: 0,\n  },\n});\n\n// 3. Configure the redux store\nconst store = createStore(combineReducers(reduxKnifeManager.getRootReducer()));\n\nconst counterKnife = reduxKnifeManager.getKnife('counter');\n// 4. The collection of action type\n// You can get the action type of increase via the following statement\nconsole.log(counterKnife.actionType.increase);\n\n// You can get the action type of decrease via the following statement\nconsole.log(counterKnife.actionType.decrease);\n\n\n// 5. The collection of action\n// You can get the increase action via the following statement\nconsole.log(counterKnife.action.increase({ value: 1 }));\n\n// You can get the decrease action via the following statement\nconsole.log(counterKnife.action.decrease({ value: 1 }));\n\n\n// 6. The collection of selector\n// You can get the whould state of counterKnife via the following statement\n// and the value should be { num: 0 }\nconsole.log(counterKnife.selector.get(store.getState()));\n\n// You can get the num value of counterKnife via the following statement\n// and the value should be 0\nconsole.log(counterKnife.selector.get(store.getState(), 'num'));\n\n\n// 7. Reducer should also work well\nstore.dispatch(counterKnife.action.increase({ value: 10 }));\n\n// You can get the num value of counterKnife via the following statement\n// and the value should be 10\nconsole.log(counterKnife.selector.get(store.getState(), 'num'));\n```\n\n\n### `getKnives()`\nThe function `getKnives` will return all knives in Redux Knife Manager.\n\n#### Returns\n* Return the **Object** which is consist of knives which are associated their `category`.\n\n#### Example\n```javascript\n// 1. Initialize Redux Knife Manager\nreduxKnifeManager.initialize();\n\n// 2. Add knives to Redux Knife Manager\nreduxKnifeManager.addKnife('k1', { ... });\nreduxKnifeManager.addKnife('k2', { ... });\nreduxKnifeManager.addKnife('k3', { ... });\n\nconst knives = reduxKnifeManager.getKnives();\n\n/*\n * The value of knives is as follow:\n * {\n *    k1: { ... },\n *    k2: { ... },\n *    k3: { ... }\n *  }\n */\n```\n\n\n### `getRootReducer()`\nThe function `getRootReducer` is used to get combined reducers of knives. It should be used to configure with redux store.\n\n#### Returns\n* Return the **Object** of combined reducer of knives which are associated with `namespace`.\n\n#### Example\n```javascript\n// 1. Initialize Redux Knife Manager\nreduxKnifeManager.initialize();\n\n// 2. Add knives to Redux Knife Manager\nreduxKnifeManager.addKnife('k1', { ... });\nreduxKnifeManager.addKnife('k2', { ... });\nreduxKnifeManager.addKnife('k3', { ... });\n\n// 3. Configure the redux store\nconst store = createStore(combineReducers(reduxKnifeManager.getRootReducer()));\n```\n\n## Todo\n* Adding the example for integrating with redux-saga\n* Adding the example for integrating with re-select\n\n## Inspired by\n* [ducks-modular-redux](https://github.com/erikras/ducks-modular-redux)\n* [reduck](https://github.com/enkidevs/reduck)\n* [dva](https://github.com/dvajs/dva)\n* [redux-actions](https://github.com/reduxactions/redux-actions)\n* [redux-act](https://github.com/pauldijou/redux-act)\n* [redux-auto](https://github.com/codemeasandwich/redux-auto)\n\n## License\nThis project is licensed under the MIT license, Copyright (c) 2018 madetheforcebewithyou. For more information, please see `LICENSE`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmadetheforcebewithyou%2Fredux-knife-manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmadetheforcebewithyou%2Fredux-knife-manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmadetheforcebewithyou%2Fredux-knife-manager/lists"}