{"id":13563325,"url":"https://github.com/smeijer/redux-define","last_synced_at":"2025-04-07T07:05:50.795Z","repository":{"id":57234788,"uuid":"74217779","full_name":"smeijer/redux-define","owner":"smeijer","description":"Define action constants for Redux","archived":false,"fork":false,"pushed_at":"2017-12-01T22:42:56.000Z","size":40,"stargazers_count":171,"open_issues_count":0,"forks_count":9,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-31T06:01:47.172Z","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/smeijer.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-11-19T15:44:22.000Z","updated_at":"2025-02-28T08:04:54.000Z","dependencies_parsed_at":"2022-09-14T12:12:18.827Z","dependency_job_id":null,"html_url":"https://github.com/smeijer/redux-define","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smeijer%2Fredux-define","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smeijer%2Fredux-define/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smeijer%2Fredux-define/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smeijer%2Fredux-define/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smeijer","download_url":"https://codeload.github.com/smeijer/redux-define/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247608150,"owners_count":20965952,"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-08-01T13:01:17.857Z","updated_at":"2025-04-07T07:05:50.739Z","avatar_url":"https://github.com/smeijer.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# redux-define\n\n[![Join the chat at https://gitter.im/smeijer/redux-define](https://badges.gitter.im/smeijer/redux-define.svg)](https://gitter.im/smeijer/redux-define?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\n[![build status](https://img.shields.io/travis/smeijer/redux-define/master.svg?style=flat-square)][1]\n\n[![NPM](https://nodei.co/npm/redux-define.png?downloads=true)][7]\n\n\n## Installation\n\nwith npm:\n```bash\nnpm install --save redux-define\n```\n\nor yarn:\n```bash\nyarn add redux-define\n```\n\nIf you don’t use [npm][2], you may grab the latest [UMD][3] build from [unpkg][4] \n(either a [development][5] or a [production][6] build). The UMD build exports a \nglobal called `window.ReduxDefine` if you add it to your page via a `\u003cscript\u003e` tag. \n\nWe *don’t* recommend UMD builds for any serious application, as most of the libraries \ncomplementary to Redux are only available on [npm][8].\n\n## Usage\n\n### `defineAction(type, ?[subactions], ?namespace)`\n\n```js\nimport { defineAction } from 'redux-define';\n```\n\nCreate a redux action type with one or more subactions:\n\n```js\nconst CREATE_TODO = defineAction('CREATE_TODO', ['ERROR', 'SUCCESS']);\n\n// result:\nconsole.log('' + CREATE_TODO);            // CREATE_TODO\nconsole.log('' + CREATE_TODO.ERROR);      // CREATE_TODO_ERROR\nconsole.log('' + CREATE_TODO.SUCCESS);    // CREATE_TODO_SUCCESS;\n```\n\nNamespaces can be used to separate actions through out modules and apps.\n\n```js\nconst CREATE_TODO = defineAction('CREATE_TODO', ['ERROR', 'SUCCESS'], 'my-app');\n\n// result:\nconsole.log('' + CREATE_TODO);            // my-app/CREATE_TODO\nconsole.log('' + CREATE_TODO.ERROR);      // my-app/CREATE_TODO_ERROR\nconsole.log('' + CREATE_TODO.SUCCESS);    // my-app/CREATE_TODO_SUCCESS;\n```\n\nIt's also possible to give in another constant as namespace for the new one.\n\n```js\nconst todos = defineAction('todos', ['LOADING', 'SUCCESS'], 'my-app');\nconst CREATE_TODO = defineAction('CREATE_TODO', ['ERROR', 'SUCCESS'], todos);\n\n// result:\nconsole.log('' + CREATE_TODO);            // my-app/todos/CREATE_TODO\nconsole.log('' + CREATE_TODO.ERROR);      // my-app/todos/CREATE_TODO_ERROR\nconsole.log('' + CREATE_TODO.SUCCESS);    // my-app/todos/CREATE_TODO_SUCCESS;\n```\n\nTo integrate better with other `redux` libraries, a special `ACTION` property is\nadded to the constant. [`redux-actions`][9] and [`redux-saga`][11] for example \ntreat actionTypes other than `string` specially. \n\nExtra benefit of this little feature, is that it makes the separation between\nuser actions and status updates more clear. Read more about this under \n[best practice](#best-practice) and [integrations](#integrations)\n\n```js\nconst CREATE_TODO = defineAction('CREATE_TODO', ['ERROR', 'SUCCESS']);\n\n// result:\nconsole.log('' + CREATE_TODO);            // CREATE_TODO\nconsole.log('' + CREATE_TODO.ACTION);     // CREATE_TODO\nconsole.log('' + CREATE_TODO.ERROR);      // CREATE_TODO_ERROR\nconsole.log('' + CREATE_TODO.SUCCESS);    // CREATE_TODO_SUCCESS;\n```\n\n### `actionType.defineAction(type, ?[subactions])`\n\nAs alternative syntax, we can use the `defineAction` method on defined constants.\nConstants defined in this way inherit their namespace. Making the namespace\nargument obsolete.\n\n```js\nconst myApp = defineAction('my-app');\nconst todos = myApp.defineAction('todos', ['LOADING', 'SUCCESS']);\nconst CREATE = todos.defineAction('CREATE', ['ERROR', 'SUCCESS']);\n```\n\nThis is the same as writing:\n\n```js\nconst myApp = defineAction('my-app');\nconst todos = defineAction('todos', ['LOADING', 'SUCCESS'], 'my-app');\nconst CREATE = todos.defineAction('CREATE', ['ERROR', 'SUCCESS'], todos);\n```\n\nOr if you only need the `CREATE` constant:\n\n```js\nconst CREATE = todos.defineAction('CREATE', ['ERROR', 'SUCCESS'], 'my-app/todos');\n```\n\nResult in these cases is the same. Except in the third case, where we only defined\nthe `CREATE` constant:\n\n```js\nconsole.log('' + myApp);                  // my-app\n\nconsole.log('' + todos);                  // my-app/todos\nconsole.log('' + todos.LOADING);          // my-app/todos_LOADING\nconsole.log('' + todos.SUCCESS);          // my-app/todos_SUCCESS\n\nconsole.log('' + CREATE);                 // my-app/todos/CREATE\nconsole.log('' + CREATE.ERROR);           // my-app/todos/CREATE_ERROR;\nconsole.log('' + CREATE.SUCCESS);         // my-app/todos/CREATE_SUCCESS;\n```\n\n### Best practice\nExtract general state constants into a separate file so they can easily be\nimported and shared across different modules:\n\n```js\n// stateConstants.js\nexport const LOADING = 'LOADING';\nexport const ERROR = 'ERROR';\nexport const SUCCESS = 'SUCCESS';\n```\n\n```js\n// app.js\nexport const myApp = defineAction('my-app');\n```\n\nIn the module; we can import the `stateConstants` and optionally parent modules\nto construct a namespace.\n\n```js\n// todos.js\nimport { defineAction } from 'redux-define';\nimport { LOADING, ERROR, SUCCESS } from './stateConstants';\nimport { myApp } from './app';\n\nconst todos = defineAction('todos', [LOADING, SUCCESS], myApp);\nconst CREATE = defineAction('CREATE', [ERROR, SUCCESS], todos);\n\n// result:\nconsole.log('' + myApp);                  // my-app\n\nconsole.log('' + todos);                  // my-app/todos\nconsole.log('' + todos.LOADING);          // my-app/todos_LOADING\nconsole.log('' + todos.SUCCESS);          // my-app/todos_SUCCESS\n\nconsole.log('' + CREATE);                 // my-app/todos/CREATE\nconsole.log('' + CREATE.ACTION);          // my-app/todos/CREATE\nconsole.log('' + CREATE.ERROR);           // my-app/todos/CREATE_ERROR\nconsole.log('' + CREATE.SUCCESS);         // my-app/todos/CREATE_SUCCESS\n```\n\nUse the `ACTION` constant in `dispatch` and in `saga watchers`. This makes it\nclear that an user or system `ACTION` is being handled. All other subtypes \nshould be `status` updates. They should be handled trough `thunks` or `sagas`, \nbut never dispatched by a user.  Although it is possible to handle user actions \nin the reducer directly, the advice is to not do this. Keep clear separation \nbetween user actions and reducer actions.\n\n### Implementation example\n\n##### stateConstants.js\n\n```js\nexport const CANCELLED = 'CANCELLED';\nexport const ERROR     = 'ERROR';\nexport const PENDING   = 'PENDING';\nexport const SUCCESS   = 'SUCCESS';\n```\n\n##### actionTypes.js\n\n```js\nimport { defineAction } from 'redux-define';\nimport { CANCELLED, ERROR, PENDING, SUCCESS } from './stateConstants';\n\nexport const DELETE_COMMENT = defineAction('DELETE_COMMENT',\n\t[CANCELLED, ERROR, PENDING, SUCCESS], 'comments');\n```\n\n##### actions.js\n\n```js\nimport { createAction } from 'redux-actions';\nimport { DELETE_COMMENT } from './actionTypes';\n\nexport const deleteComment = createAction(DELETE_COMMENT.ACTION);\n```\n\n##### reducer.js\n\n```js\nimport { handleActions, combineActions } from 'redux-actions';\nimport { DELETE_COMMENT } from './actionTypes';\n\nconst initialState = {\n  isDeleting: false,\n};\n\nconst reducer = handleActions({\n  [DELETE_COMMENT.PENDING]: state =\u003e ({\n    ...state,\n    isDeleting: true,\n  }),\n\n  [combineActions(\n    DELETE_COMMENT.CANCELLED,\n    DELETE_COMMENT.SUCCESS,\n    DELETE_COMMENT.ERROR,\n  )]: state =\u003e ({\n    ...state,\n    isDeleting: false,\n  }),\n}, initialState);\n```\n\n##### sagas.js\n\n```js\nimport { call, put, take } from 'redux-saga/effects';\nimport deleteAPI from 'somewhere-out-of-this-scope';\nimport { DELETE_COMMENT } from './actionTypes';\n\nexport function* deleteComment({ payload }) {\n  try {\n    yield put({ type: DELETE_COMMENT.PENDING });\n    const { data } = yield call(deleteAPI, payload);\n    yield put({ type: DELETE_COMMENT.SUCCESS, payload: data });\n  }\n  catch (error) {\n    yield put({ type: DELETE_COMMENT.ERROR, payload: { error: error.message } });\n  }\n}\n```\n\n##### watchers.js\n\n```js\nimport { takeEvery } from 'redux-saga';\nimport { fork } from 'redux-saga/effects';\n\nimport { DELETE_COMMENT } from './actionTypes';\nimport * as s from './sagas';\n\nfunction* deleteCommentWatcher() {\n  yield* takeEvery(DELETE_COMMENT.ACTION, s.deleteComment);\n}\n\nexport default function* () {\n  yield [\n    fork(deleteCommentWatcher),\n  ];\n}\n\n```\n\n### Why use `redux-define`? \nThis library reduces a lot of the boilerplate that comes with defining redux\naction types. This library is created as solution to [organizing large ducks][10]\nLet's show the difference here. See above for a full [implementation example](#implementation-example).\nWhen using `ducks`, some of the files in the example above should be joined into\na single duck file.\n\nWithout using `redux-define`\n\n```js\nconst CREATE_TODO = 'CREATE_TODO';\nconst CREATE_TODO_PENDING = 'CREATE_TODO_PENDING';\nconst CREATE_TODO_ERROR = 'CREATE_TODO_ERROR';\nconst CREATE_TODO_SUCCESS = 'CREATE_TODO_SUCCESS';\n\nconst DELETE_TODO = 'DELETE_TODO';\nconst DELETE_TODO_PENDING = 'DELETE_TODO_PENDING';\nconst DELETE_TODO_CANCELLED = 'DELETE_TODO_CANCELLED';\nconst DELETE_TODO_ERROR = 'DELETE_TODO_ERROR';\nconst DELETE_TODO_SUCCESS = 'DELETE_TODO_SUCCESS';\n```\n\nWith `redux-define`\n\n```js\nimport { defineAction } from 'redux-define';\nimport { PENDING,  CANCELLED, ERROR, SUCCESS } from '/lib/stateConstants.js';\n\nconst CREATE_TODO = defineAction('CREATE_TODO', [PENDING, ERROR, SUCCESS]);\nconst DELETE_TODO = defineAction('DELETE_TODO', [PENDING, CANCELLED, ERROR, SUCCESS]);\n```\n\n### Integrations\n\nCreated constants can be directly used in [`sagas`][11] `reducers`, or together \nwith [`redux-actions`][9].\n\nSee [implementation example](#implementation-example) in this readme for implementation\ndetails. We handle [`redux-actions`][9] in [actions.js](#actionsjs) and \n[reducer.js](#reducerjs) and [`redux-saga`][11] in [watchers.js](#watchersjs)\nand [sagas.js](#sagasjs).\n\n[1]: https://travis-ci.org/smeijer/redux-define\n[2]: https://www.npmjs.com\n[3]: https://unpkg.com/redux-define@latest/dist\n[4]: https://unpkg.com\n[5]: https://unpkg.com/redux-define@latest/dist/redux-define.js\n[6]: https://unpkg.com/redux-define@latest/dist/redux-define.min.js\n[7]: https://nodei.co/npm/redux-define\n[8]: https://www.npmjs.com/search?q=redux\n[9]: https://github.com/acdlite/redux-actions\n[10]: https://github.com/erikras/ducks-modular-redux/issues/16\n[11]: https://github.com/yelouafi/redux-saga\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmeijer%2Fredux-define","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmeijer%2Fredux-define","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmeijer%2Fredux-define/lists"}