{"id":15697457,"url":"https://github.com/thk2b/redux-structures","last_synced_at":"2025-05-09T00:58:43.245Z","repository":{"id":57351702,"uuid":"129418460","full_name":"thk2b/redux-structures","owner":"thk2b","description":"Reusable redux data structures","archived":false,"fork":false,"pushed_at":"2018-05-15T23:16:10.000Z","size":70,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-05-09T00:58:36.972Z","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/thk2b.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-04-13T15:08:33.000Z","updated_at":"2018-05-15T23:16:11.000Z","dependencies_parsed_at":"2022-09-18T23:50:43.502Z","dependency_job_id":null,"html_url":"https://github.com/thk2b/redux-structures","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thk2b%2Fredux-structures","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thk2b%2Fredux-structures/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thk2b%2Fredux-structures/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thk2b%2Fredux-structures/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thk2b","download_url":"https://codeload.github.com/thk2b/redux-structures/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253171250,"owners_count":21865290,"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-10-03T19:20:06.028Z","updated_at":"2025-05-09T00:58:43.218Z","avatar_url":"https://github.com/thk2b.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# redux-strucures\nReusable idiomatic redux data structures.\n\n[![npm version](https://badge.fury.io/js/redux-structures.svg)](https://badge.fury.io/js/redux-structures)\n[![Open Source Love](https://badges.frapsoft.com/os/mit/mit.svg?v=102)](https://github.com/ellerbrock/open-source-badge/)\n\n```\nnpm install --save redux-structures\n```\n\n## Docs\n\n- [Value](https://github.com/thk2b/redux-structures/blob/master/src/Value/docs.md)\n- [HashMap](https://github.com/thk2b/redux-structures/blob/master/src/HashMap/docs.md)\n- [List](https://github.com/thk2b/redux-structures/blob/master/src/List/docs.md)\n\n## Motivation\n\nRedux applications often implement the same reducer logic. For instance, adding or removing a property from a state object, inserting an element to a list or updating a value. `redux-structures` provides reusable implementations of these common data structures so that you do not have to rewrite the same reducers over and over.\n\nTo illustrate the problem, consider a chat application. The store has `users` and `messages`, which are both objects:\n\n```js\nstore.getState()\n/*\n{\n  users: {\n    1: { id: 1, name: 'john doe', ... }\n    2: { id: 2, name: 'jane doe', ... }\n    ...\n  },\n  messages: {\n    1: { id: 1, text: 'hello, world', userId: 1, ...}\n    2: { id: 2, text: 'what\\'s up ?', userId: 2, ...},\n    ...\n  }\n}\n*/\n```\n\nCommon actions include adding or removing a user, as well as adding or removing a message.\n\n```js\nfunction users(state, action){\n  switch(action.type){\n    case ADD_USER: return {...state, [action.user.id]: action.user}\n    ...\n  }\n}\n\nfunction messages(state, action){\n  switch(action.type){\n    case ADD_MESSAGE: return {...state, [action.message.id]: action.message}\n    ...\n  }\n}\n```\nNotice that the only difference between the two reducers are the constants and the action property names. The same error-prone logic is repeated twice.\n\n`redux-structures` implements this logic *once*, and allows you to instantly create coupled reducers and actions.\n\n```js\nimport { HashMap } from 'redux-structures'\n\nconst { reducer: users, actions: userActions} = HashMap('users')\nconst { reducer: messages, actions: messageActions} = HashMap('messages')\n\n```\nNow, to add a user, simply dispatch `userActions.set(id, user)`. (See the documentation for more information)\n\nThis has several advantages.\n\n- Faster and safer development\n- You no longer need to unit-test individual reducers, since they tested once at the library level.\n\n## Concepts\n\n`redux-structures` employs two core concepts.\n\n- Structures\n\n  Structures are functions that return a reducer and actions. There are different types of structures: `Value`, `HashMap`, and `List`.\n- Instances\n\n  Instances are reducer - actions pairs, obtained by calling a structure. Instances are created with a unique name, so that actions only affect the reducer to which they are bound, and not reducers from other instances of the same structure. Actions and reducers are coupled: reducers only match actions created by the instance's action creators. In our example, an instance would be `messages` and `messagesAction`.\n\n## Patterns\n\n`redux-structures` provides basic level operations, and does not get in the way of your application-specific needs. You can dispatch the actions from anywhere in your app - from the view, middleware, or thunk like you do with traditional actions. \n\n### Higher order action creators\n\nYou can define higher-order actions, which take a parameter and return another action creator. Consider what happens a user submits a new message, in the earlier example. \n\n```js\nconst { reducer: messages, actions: messageActions} = HashMap('messages')\n\nconst createMessage = text =\u003e {\n  const id = generateId()\n  const message = {\n    text,\n    sentAt: Date.now(),\n    id\n  }\n  return messageActions.set(id, message)\n}\n```\n\nHere, the `create` action returns another more general action creator.\n\n### Using middleware\n\nActions from `redux-structures` can be dispatched from anywhere, including middleware.\n\n### Composing reducers\n\nYou can define reducers which contain reducers from `redux-structures`.\n\n## Usage\n\nIt is recomended to export instances from their own module, like in traditional redux applications. Then, import all reducers when creating the store, and import actions where necesary.\n\n`messages.js`\n```js\nimport { HashMap } from 'redux-structures'\nconst { reducer, actions } = HashMap('messages')\n\n/* define custom actions, in this case with the thunk middleware */\n\nfunction fetchMessage(id){\n    return dispatch =\u003e {\n        fetch(`/message/${id}`)\n            .then(message =\u003e dispatch(actions.set(id, message)))\n    }\n}\nfunction fetchMessages(){\n    return dispatch =\u003e {\n        fetch(`/messages`)\n            .then(messages =\u003e {\n                dispatch(actions.setAll(messages))\n            })\n   }\n}\n\nconst messageActions = {\n  ...actions,\n  fetchMessage,\n  fetchMessages\n}\n\nexport { messageActions }\nexport default reducer\n```\n`index.js`\n```js\nimport { createStore, combineReducers } from 'redux'\nimport messages from './path/to/messages'\nimport users from './path/to/users'\n\nexport default createStore(\n  combineReducers({\n    messages,\n    users\n  })\n)\n```\n`view.js`\n```js\nimport { messageActions } from './path/to/messages'\n\n/* import actions and dispatch as you wish */\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthk2b%2Fredux-structures","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthk2b%2Fredux-structures","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthk2b%2Fredux-structures/lists"}