{"id":17159260,"url":"https://github.com/akuzko/react-redux-connector","last_synced_at":"2026-05-06T23:31:58.677Z","repository":{"id":57343201,"uuid":"70425667","full_name":"akuzko/react-redux-connector","owner":"akuzko","description":"Object-oriented React binding for Redux","archived":false,"fork":false,"pushed_at":"2017-02-26T19:42:41.000Z","size":16,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-29T19:47:18.483Z","etag":null,"topics":["react","reducer-creation","redux","redux-connect","redux-state"],"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/akuzko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-10-09T19:30:57.000Z","updated_at":"2018-08-07T22:01:42.000Z","dependencies_parsed_at":"2022-09-17T06:00:34.159Z","dependency_job_id":null,"html_url":"https://github.com/akuzko/react-redux-connector","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akuzko%2Freact-redux-connector","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akuzko%2Freact-redux-connector/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akuzko%2Freact-redux-connector/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akuzko%2Freact-redux-connector/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/akuzko","download_url":"https://codeload.github.com/akuzko/react-redux-connector/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245294723,"owners_count":20591898,"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","reducer-creation","redux","redux-connect","redux-state"],"created_at":"2024-10-14T22:13:48.803Z","updated_at":"2026-05-06T23:31:53.641Z","avatar_url":"https://github.com/akuzko.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"React Redux Connector\n=====================\n\nObject-oriented React bindings for [Redux](https://github.com/reactjs/redux).\n\n[![build status](https://img.shields.io/travis/akuzko/react-redux-connector/master.svg?style=flat-square)](https://travis-ci.org/akuzko/react-redux-connector)\n[![npm version](https://img.shields.io/npm/v/react-redux-connector.svg?style=flat-square)](https://www.npmjs.com/package/react-redux-connector)\n\n## Installation\n\n```\nnpm install --save react-redux-connector\n```\n\n## Requirements\n\nCurrently, `react-redux-connector` is available only as [npm](http://npmjs.com/) package.\nTo effectively work with the library, you will also have to use transpiler like\n[babel](https://babeljs.io/) with [es2015-classes](https://babeljs.io/docs/plugins/transform-es2015-classes)\nand [class-properties](https://babeljs.io/docs/plugins/transform-class-properties) features enabled.\n\n## Motivation\n\nPretty quickly after starting using `react-redux` I started to feel uncomfortability of having\nmy actions, reducer definitions and component code that actually uses former scattered among\ndifferent files and places in the application. Also, I didn't like nor huge switch-case\nreducer functions, nor lots of same-looking small reducer functions each of which\naccepts repetitive (state, action) arguments pair. As a Rails developer, I felt a need of\nsome kind of separate abstraction layer that will hoist all the redux-specific logic\nin a declarative and DRY way. That's how the concept of redux `Connector` component was born.\n\n## Documentation\n\n`react-redux-connector` is inspired by Dan Abramov's awesome [react-redux](https://github.com/reactjs/react-redux)\nlibrary. At it's lowest level it uses react-redux's subscription mechanism to\nredux store (this part of code was ported from react-redux), however, `react-redux-connector`\nprovides completely different way of organizing react-related logic of your\napplication and it's usage. `react-redux-connector` exports `Connector`, `Connection`\nand `Reductor` classes, the most important of which is, unsuprisingly, the `Connector` class.\n\n### Connector\n\nEach Connector hoists all react-related logic (reducer functions, actions,\ndispatching, etc) and provides bindings for your React components (which are\ncalled connections).\n\n#### API\n\nConnector classes should have following properties set up:\n\n- `static $connection` - the React component (view layer) that Connector provides\nconnections for.\n\n- `static $state` - the initial redux state that will be used in reducer function.\n\n- `static $namespace` - the path of connector's `$state` in full redux's state.\nShould be something like `'profile.show'` or `'todos.list'`. It is also used\nfor generation of action types (which will look like `'profile.show/$receive'`).\nThis property is set automatically in `Connector.reduce` function that generates\nrequired `$reducer` function (see bellow). But if connector only provides data\nwith no action handling, appropriate `$namespace` should be set explicitly.\nDefaults to `'global'`.\n\n- `static $reducer` - a reducer function that should be generated with `Connector.reduce`\nfunction. **This function should be called on behalf of your connector**, i.e.\n`static $reducer = TodosConnector.reduce(...)`. This function should be called like this:\n\n```js\nstatic $reducer = YourConnector.reduce('your.namespace', (state) =\u003e ({\n  $actionOne: (arg) =\u003e newState,\n  $otherAction: (arg1, arg2) =\u003e anotherNewState\n}));\n```\n\nBy calling `reduce` in this way, your connector's prototype gets `$$actionOne` and\n`$$otherAction` methods that will **dispatch** corresponding action that will\ntrigger corresponding reducer's code with arguments you've passed.\n\n- `$expose` instance method that should return object that will be passed\nto $connection component in props. Yes, you can think of it as react-redux's\n`mapStateToProps`. This method accepts 2 arguments: `$state` which is\ncurrent connector's state (i.e. part of the full state under connector's namespace)\nand `state`, which is full redux state. Defaults to function that simply returns `$state`.\n\n#### $-functions\n\nAll functions in connector's prototype that start with *exactly one* '$' sign\nwill be available in connector's connection component and all other nested\nconnection components.\n\n#### Example\n\n```js\nimport { Connector } from 'react-redux-connector';\nimport Todos from './Todos';\nimport { get, post, put, destroy } from 'your-requests-lib';\n\nexport default class TodosConnector extends Connector {\n  static $connection = Todos;\n  static $state = [];\n  static $reducer = TodosConnector.reduce('todos', (state) =\u003e ({\n    $receive: (items) =\u003e items,\n    $addItem: (item) =\u003e [...state, item],\n    $updateItem: (item) =\u003e state.map(i =\u003e i.id === item.id ? item : i),\n    $removeItem: (id) =\u003e state.filter(i =\u003e i.id !== id)\n  }));\n\n  $expose($state) {\n    return { items: $state };\n  }\n\n  $load() {\n    return get('/todos')\n      .then(response =\u003e this.$$receive(response.data));\n  }\n\n  $create(item) {\n    return post('/todos', { item })\n      .then(response =\u003e this.$$addItem(response.data));\n  }\n\n  $update(item) {\n    return put(`/todos/${item.id}`, { item })\n      .then(response =\u003e this.$$updateItem(response.data));\n  }\n\n  $destroy(id) {\n    return destroy(`/todos/${id}`)\n      .then(() =\u003e this.$$removeItem(id));\n  }\n}\n```\n\n#### External actions dispatching\n\nIf there is a need to dispatch an action of other Connector, i.e. from other namespace,\nthat can be done using `#dispatch` and `.action` methods, like so:\n\n```js\n// somewhere in TodosConnector.jsx\n\n$createTodo(todo) {\n  return post('/todos', { todo })\n    .then(() =\u003e this.dispatch(ToolbarConnector.action('incrementTodosCount')));\n}\n```\n\n### Connection\n\nConnection is a very simple helper object that you should inherit from instead of\n`React.Component`. Connection components can call all $-starting methods that\nare defined in Connector (that intended to result in dispatching an action).\n\nNote that only explicitly connected connection (i.e. the one that is specified\nin connector's $connection property) gets connector's exposed state in properties.\nAll other connections nested under that 'main' one have usual props that you've\npassed to them via React means, but they **do** have access to connector's $-functions.\n\n#### Example\n\n```js\nimport { Connection } from 'react-redux-connector';\n\nexport default class Todos extends Connection {\n  state = { title: '' };\n\n  componentDidMount() {\n    this.$load();\n  }\n\n  saveItem() {\n    this.$create({ title: this.state.title })\n      .then(() =\u003e this.setState({ title: '' }));\n  }\n\n  destroyItem(id) {\n    this.$destroy(id);\n  }\n\n  render() {\n    return (\n      \u003cdiv\u003e\n        {this.props.items.map(item =\u003e\n          \u003cdiv key={item.id}\u003e\n            {item.title}\n            \u003cbutton onClick={() =\u003e this.destroyItem(item.id)}\u003eDelete\u003c/button\u003e\n          \u003c/div\u003e\n        )}\n        \u003cinput onChange={(e) =\u003e this.setState({ title: e.target.value })} /\u003e\n        \u003cbutton onClick={() =\u003e this.saveItem()}\u003eSave\u003c/button\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n```\n\n**NOTE:** if you don't want to inherit from `Connection`, you can gain access to\nconnector's $-functions using react context:\n\n```js\nclass Todos extends Component {\n  static contextTypes = {\n    on: PropTypes.object\n  };\n\n  componentDidMount() {\n    this.context.on.$load();\n  }\n\n  // ...\n}\n```\n\nActually, that's only one thing Connection does - provides a kind of syntactic\nsugar for calling connector's $-functions.\n\n### Reductor\n\nReductor is a special helper component that acts as react-redux's state provider,\nbut it's main purpose is to generate a store reducer function for you. On initialization\nit will traverse all children tree looking for connectors, collect them and use\nto create and provide store with given createStore prop. Connectors that are not\npresent in the children tree should be listed in `connectors` property. Naturally,\nthe most obvious example is usage with [react-router](https://www.npmjs.com/package/react-router)\nroutes.\n\n```js\nimport { Reductor } from 'react-redux-connector';\nimport { createStore } from 'redux';\n\nimport Profile from 'application/ProfileConnector';\nimport Todos from 'application/todos/TodosCollector';\nimport TodoDetails from 'application/todos/TodoDetailsConnector';\n\nexport default class App extends Component {\n  return (\n    \u003cReductor createStore={createStore}\u003e\n      \u003cRouter history={history}\u003e\n        \u003cIndexRedirect to=\"/profile\" /\u003e\n        \u003cRoute path=\"/profile\" component={Profile} /\u003e\n        \u003cRoute path=\"/todos\" component={Todos} /\u003e\n        \u003cRoute path=\"/todos/:id\" component={TodoDetails} /\u003e\n      \u003c/Router\u003e\n    \u003c/Reductor\u003e\n  );\n}\n```\n\n#### Reductor Props\n\n| Prop Name       | Spec                                                     | Description |\n|-----------------|----------------------------------------------------------|-------------|\n| `createStore`   | **required** `PropTypes.func`                            | A function that takes reducer function (generated by a Reductor) as an argument and returns a redux state |\n| `connectors`    | *optional* `PropTypes.arrayOf(PropTypes.func)`           | An array of connectors that cannot be mentioned in children tree, but whose `$reducer` functions should become a part of generated redux reducer function |\n| `connectorProp` | *optional* `PropTypes.string`, defaults to `'component'` | A prop of components in children tree that contains a Connector as a value |\n\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakuzko%2Freact-redux-connector","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakuzko%2Freact-redux-connector","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakuzko%2Freact-redux-connector/lists"}