{"id":40347696,"url":"https://github.com/vshushkov/redux-models","last_synced_at":"2026-01-20T09:31:17.916Z","repository":{"id":13968081,"uuid":"75540925","full_name":"vshushkov/redux-models","owner":"vshushkov","description":"Models layer for your Redux application","archived":false,"fork":false,"pushed_at":"2023-01-03T15:15:18.000Z","size":1514,"stargazers_count":1,"open_issues_count":12,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-12-15T20:24:54.494Z","etag":null,"topics":["graphql","models","react","redux","redux-models","rest-api"],"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/vshushkov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-12-04T14:02:04.000Z","updated_at":"2021-03-02T04:54:37.000Z","dependencies_parsed_at":"2023-01-13T17:43:19.393Z","dependency_job_id":null,"html_url":"https://github.com/vshushkov/redux-models","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/vshushkov/redux-models","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vshushkov%2Fredux-models","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vshushkov%2Fredux-models/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vshushkov%2Fredux-models/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vshushkov%2Fredux-models/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vshushkov","download_url":"https://codeload.github.com/vshushkov/redux-models/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vshushkov%2Fredux-models/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28600461,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T08:51:33.170Z","status":"ssl_error","status_checked_at":"2026-01-20T08:51:10.855Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["graphql","models","react","redux","redux-models","rest-api"],"created_at":"2026-01-20T09:31:17.846Z","updated_at":"2026-01-20T09:31:17.904Z","avatar_url":"https://github.com/vshushkov.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Redux models\n\n[![Build](https://travis-ci.org/vshushkov/redux-models.svg?branch=master)](https://travis-ci.org/vshushkov/redux-models)\n[![Test Coverage](https://codeclimate.com/github/vshushkov/redux-models/badges/coverage.svg)](https://codeclimate.com/github/vshushkov/redux-models/coverage)\n\nModels layer for Redux. `redux-models` simplifies working with remote data (well.. not only remote) and helps to organize your code.\n\n## Installation\n\n```bash\nnpm install --save redux redux-models\n```\n\n## Usage\n\n##### `models/User.js`\n\n```js\nimport { createModel } from 'redux-models';\n\nexport default createModel({\n  name: 'User',\n  methods: {\n    findByUsername(username) {\n      return fetch(`https://api.github.com/users/${username}`).then(res =\u003e\n        res.json()\n      );\n    }\n  }\n});\n```\n\n##### `store.js`\n\n```js\nimport { combineReducers, applyMiddleware, createStore } from 'redux';\nimport thunk from 'redux-thunk';\nimport User from './models/User';\n\nexport default createStore(\n  combineReducers({\n    ...User.reducers\n  }),\n  applyMiddleware(thunk)\n);\n```\n\n##### `app.js`\n\n```jsx harmony\nimport React from 'react';\nimport { connect } from 'react-redux';\nimport User from './models/User';\n\nclass UserAvatar extends React.Component {\n  componentDidMount() {\n    const { fetchUser } = this.props;\n    fetchUser();\n  }\n\n  render() {\n    const { user } = this.props;\n\n    if (!user) {\n      return \u003cdiv\u003eLoading...\u003c/div\u003e;\n    }\n\n    return \u003cimg src={user.avatar_url} alt=\"avatar\" /\u003e;\n  }\n}\n\nexport default connect(\n  (state, { username }) =\u003e ({\n    user: User(state).findByUsername(username)\n  }),\n  (dispatch, { username }) =\u003e ({\n    fetchUser: () =\u003e dispatch(User.findByUsername(username))\n  })\n)(UserAvatar);\n```\n\n[Live demo](https://codesandbox.io/s/redux-models-example-j74p7)\n\n## API\n\n### `createModel(options)`\n\n#### Arguments\n\n`options`:\n\n- `options.name`: (`String`): Name of a model\n- `options.mixins`: (`Array`): Array of mixins\n- `options.methods`: (`Object`): Model's methods\n- `options.reducer`: (`Function` [optional]): [Model reducer](#model-reducer).\n- `options.typePrefix`: (`String` [optional]): Prefix of actions types. Default `@@redux-models`.\n- `options.modelState`: (`Function` [optional]): Function to map state to model state. Default `state =\u003e state[{ model name }]`.\n\n#### Returns\n\nNewly created model with defined methods. Each model method creates action to dispatch.\n\n### Model reducer\n\nAdditional data processing from the methods can be done in the model reducer.\n\nModel reducer arguments are same as [redux reducers](https://redux.js.org/basics/reducers), except the last argument `types`.\nIt contains all action types strings your model can dispatch (including mixins action types).\nIn following example model `User` has one method `find` and it can dispatch actions with types: `@@redux-models/USER/FIND`, `@@redux-models/USER/FIND_SUCCESS`, `@@redux-models/USER/FIND_ERROR`, `@@redux-models/USER/FIND_RESET`,\nso `types` contains object:\n\n```json5\n{\n  FIND: '@@redux-models/USER/FIND',\n  find: '@@redux-models/USER/FIND',\n  FIND_SUCCESS: '@@redux-models/USER/FIND_SUCCESS',\n  findSuccess: '@@redux-models/USER/FIND_SUCCESS',\n  FIND_ERROR: '@@redux-models/USER/FIND_ERROR',\n  findError: '@@redux-models/USER/FIND_ERROR',\n  FIND_RESET: '@@redux-models/USER/FIND_RESET',\n  findReset: '@@redux-models/USER/FIND_RESET'\n}\n```\n\nAfter processing, the data will be available in `state.{ model name }.model`.\n\n#### Example\n\n```js\nimport { createModel } from 'redux-models';\n\nconst defaultState = {\n  byId: {}\n};\n\nexport default createModel({\n  name: 'User',\n  methods: {\n    find(query) {\n      // async request\n    }\n  },\n  reducer(state = defaultState, action, { findSuccess }) {\n    const { type, payload: { result } = {} } = action;\n\n    if (type === findSuccess) {\n      return {\n        ...state,\n        byId: {\n          ...state.byId,\n          ...(result || []).reduce(\n            (byId, user) =\u003e ({\n              ...byId,\n              [user.id]: user\n            }),\n            {}\n          )\n        }\n      };\n    }\n\n    return state;\n  }\n});\n```\n\nThen:\n\n```jsx harmony\nimport { connect } from 'react-redux';\n// ...\n\nexport default connect((state, { id }) =\u003e ({\n  user: state.User.model.byId[id]\n}))(UserCard);\n```\n\n## Mixins\n\nMixins allow you to add method sets to multiple models. For example mixin \n[`crud`](https://www.npmjs.com/package/redux-models-mixin-crud)\nadds methods: `create`, `updateById`, `deleteById`, `find`, `findById`.\n\n##### `crud.js`\n\n```jsx harmony\nimport createMixin from 'redux-models-mixin-crud';\n\nexport default function crudMixin(path) {\n  return createMixin({ \n    methods: {\n      create() { /*...*/ },\n      updateById() { /*...*/ },\n      deleteById() { /*...*/ },\n      find() { /*...*/ },\n      findById() { /*...*/ }\n    } \n  });\n}\n```\n\n##### `book.js`\n\n```jsx harmony\nimport { createModel } from 'redux-models';\nimport crudMixin from './crud';\n\nexport default createModel({\n  name: 'Book',\n  mixins: [crudMixin('/books')]\n});\n```\n\n## Contributing\n\nSee the [Contributors Guide](https://github.com/vshushkov/redux-models/blob/master/CONTRIBUTING.md)\n\nLicense\n[MIT](https://github.com/vshushkov/redux-models/blob/master/LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvshushkov%2Fredux-models","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvshushkov%2Fredux-models","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvshushkov%2Fredux-models/lists"}