{"id":23157898,"url":"https://github.com/roblafeve/redux-factory","last_synced_at":"2025-08-18T00:33:21.904Z","repository":{"id":57350674,"uuid":"61096111","full_name":"roblafeve/redux-factory","owner":"roblafeve","description":"Composable, curried factory for creating Redux reducers and actions","archived":false,"fork":false,"pushed_at":"2017-03-16T20:24:37.000Z","size":20,"stargazers_count":9,"open_issues_count":3,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-17T15:53:37.176Z","etag":null,"topics":["actions","composable","curried","fp","reducer","redux","redux-factory","state","store"],"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/roblafeve.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":"2016-06-14T06:04:55.000Z","updated_at":"2021-08-10T05:47:29.000Z","dependencies_parsed_at":"2022-09-15T02:01:53.543Z","dependency_job_id":null,"html_url":"https://github.com/roblafeve/redux-factory","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roblafeve%2Fredux-factory","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roblafeve%2Fredux-factory/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roblafeve%2Fredux-factory/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roblafeve%2Fredux-factory/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/roblafeve","download_url":"https://codeload.github.com/roblafeve/redux-factory/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230164275,"owners_count":18183365,"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":["actions","composable","curried","fp","reducer","redux","redux-factory","state","store"],"created_at":"2024-12-17T22:16:16.057Z","updated_at":"2024-12-17T22:16:17.103Z","avatar_url":"https://github.com/roblafeve.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Redux Factory\n\n[![codecov](https://codecov.io/gh/roblafeve/redux-factory/branch/master/graph/badge.svg)](https://codecov.io/gh/roblafeve/redux-factory)\n[![Build Status](https://travis-ci.org/roblafeve/redux-factory.svg?branch=master)](https://travis-ci.org/roblafeve/redux-factory)\n\nComposable, curried factory for creating Redux reducers and actions. Being curried, you can supply an initial state and define your actions, but omit the prefix argument that is required to finally generate your `actionCreator` and `reducer` functions. Doing this allows you to export a base configuration to be used in any number of distinct portions of your state tree.\n\nBeyond this, Redux Factory provides a `compose` function that allows you to combine any number of un-prefixed factories in order to maximize flexibility and code reuse.\n\n\u003e Note: This library embraces some basic ideas from functional programing (curry, compose). While I believe these are powerful tools, this may not be your _'cup of tea'_ ☕. If not, you may consider using [redux-act](https://github.com/pauldijou/redux-act).\n\n## Install\n\n```\n$ npm install --save redux-factory\n```\n\n## Usage\n\n### Basic\n```js\nimport factory from 'redux-factory'\nimport { merge } from 'ramda' // or bring your own object merge\n\nconst prefix = 'users' // `String` or `false`\n\nconst initialState = { // required by Redux\n  list: [],\n  activity: false,\n  location: {}\n}\n\nconst actions = {\n  add: (state, payload) =\u003e merge(state, {list: [...state, payload]}),\n  setActivity: (state, payload) =\u003e merge(state, {activity: payload}),\n  'UPDATE_LOCATION': {\n    transform: (state, payload) =\u003e merge(state, {location: payload}),\n    prefix: false, // Action type will be 'as-is' regardless of prefix passed to factory\n    meta: {} // Some middleware utilizes this\n  }\n}\n\nexport default factory(initialState, actions, prefix) // factory :: (Object, Object, String|False) -\u003e Object\n// The above code exports an object for use in your app:\n// {\n//   add: [Function],\n//   setActivity: [Function],\n//   UPDATE_LOCATION: [Function],\n//   reducer: [Function]\n// }\n```\n\u003e Notes:\n- The case of your prefix and action keys _DO_ matter (this is the main breaking change with `3.0.0`—as they were always normalized). This allows you to format your action keys as you see fit. Also, with the addition of the alternate action config syntax (see above) which allows you to set the prefix to `false` on a per-action basis, it is now possible to handle a third-party action in any piece of your state (e.g. users could handle `UPDATE_LOCATION` from `redux-simple-router`).\n- Why the prefix? Namespace is all that distinguishes your action types. Unless your state is extremely simple they are very handy. Nevertheless, you may pass `false` as a third argument if you don't want it.\n\n### Curried and composed\n```js\nimport factory, { compose } from 'redux-factory'\nimport { merge } from 'ramda' // or bring your own object merge\n\nconst listInitialState = { // required by Redux\n  list: [],\n  activity: false\n}\n\nconst listActions = {\n  add: (state, payload) =\u003e merge(state, {list: [...state, payload]}),\n  setActivity: (state, payload) =\u003e merge(state, {activity: payload})\n}\n\nconst list = factory(listInitialState, listActions) // factory :: (Object, Object) -\u003e Function\n\nconst prefix = 'dogs'\n\nconst dogsInitialState = {\n  barking: false,\n  pooping: false,\n  running: false\n}\n\nconst dogsActions = {\n  barking: (x, y) =\u003e merge(x, { barking: y }),\n  pooping: (x, y) =\u003e merge(x, { pooping: y }),\n  running: (x, y) =\u003e merge(x, { running: y })\n}\n\nconst dogs = factory(dogsInitialState, dogsActions) // factory :: (Object, Object) -\u003e Function\n\nexport default compose(list, dogs, prefix) // compose :: (Function, ..., String) -\u003e Object\n// The above code exports an object for use in your app:\n// {\n//   add: [Function],\n//   setActivity: [Function],\n//   barking: [Function],\n//   pooping: [Function],\n//   running: [Function],\n//   reducer: [Function]\n// }\n```\n\u003e Notes:\n- Compose will take any number of unprefixed factory functions\n- Compose itself is curried which means you can supply it with a complex set of factories for composition, then apply any number of prefixes later.\n- Compose can take other unprefixed compositions along with additional unprefixed factories and combine them into a single object. The sky is the limit.\n\n## API\n\n### Factory\n- Type Signature ([Guide to Type Signatures](https://github.com/ramda/ramda/wiki/Type-Signatures)):\n```js\n//  Factory :: InitialState → {k: Transform} → Prefix → {k: ActionCreator, reducer: Reducer}\n//          :: InitialState → {k: Config} → Prefix → {k: ActionCreator, reducer: Reducer}\n//          Action        = {type: String, payload: Payload, error: Bool, meta: a }\n//          ActionCreator = Payload → Action\n//          Config        = {transform: Transform, prefix: Bool, meta: a}\n//          InitialState  = a\n//          Payload       = a\n//          Prefix        = String\n//          Reducer       = (State, Action) → State\n//          State         = a\n//          Transform     = (State, Payload) → State\n```\n- Curried: `true` (all arguments may be partially applied)\n- Parameters:\n  - **initialState**: object required by redux\n  - **actions**: object of action methods (e.g. `{ actionName: (state, payload) =\u003e Object.assign({}, state, {name: payload}) }`)\n    - `state` current state\n    - `payload` action payload\n  - **prefix**: string used to create unique actions and reducers\n- Returns `Object` with action method(s) and a reducer method to export and use in your app:\n\n```js\n{\n  add: [Function],\n  setActivity: [Function],\n  barking: [Function],\n  pooping: [Function],\n  running: [Function],\n  reducer: [Function]\n}\n```\n\n### Compose\n- Signature: `(Function: unprefixed Factory || unprefixed Compose, ..., String: prefix) -\u003e Object`\n- Curried: `true` (if a string prefix is not applied as final argument)\n- Parameters:\n  - **All but last**: unprefixed Factory or Compose functions\n  - **Last**: prefix string used to create unique actions and reducers\n\n## Tips\n1. Use a helper to merge old and new state (e.g. Ramda's [merge](http://ramdajs.com/0.21.0/docs/#merge)). Originally, `redux-factory` automatically merged old/new state, but this proved unintuitive.\n\n```js\nimport { merge } from 'ramda'\n// Much better!\nconst actions = {\n  myAction: (x, y) =\u003e merge(x, {name: y})\n}\n```\n\n## License\n\nMIT © [Rob LaFeve](https://twitter.com/roblafeve)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froblafeve%2Fredux-factory","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Froblafeve%2Fredux-factory","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froblafeve%2Fredux-factory/lists"}