{"id":15679176,"url":"https://github.com/neurosnap/redux-cofx","last_synced_at":"2025-05-07T10:35:43.488Z","repository":{"id":47998193,"uuid":"141206660","full_name":"neurosnap/redux-cofx","owner":"neurosnap","description":"declarative redux middleware for handling side-effects","archived":false,"fork":false,"pushed_at":"2022-12-09T14:35:43.000Z","size":403,"stargazers_count":12,"open_issues_count":3,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-19T21:24:32.960Z","etag":null,"topics":["middleware","redux","redux-saga","redux-thunk","saga","side-effects","thunk"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/neurosnap.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2018-07-16T23:46:29.000Z","updated_at":"2024-03-24T19:56:05.000Z","dependencies_parsed_at":"2023-01-25T14:15:15.404Z","dependency_job_id":null,"html_url":"https://github.com/neurosnap/redux-cofx","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neurosnap%2Fredux-cofx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neurosnap%2Fredux-cofx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neurosnap%2Fredux-cofx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neurosnap%2Fredux-cofx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neurosnap","download_url":"https://codeload.github.com/neurosnap/redux-cofx/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252860496,"owners_count":21815525,"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":["middleware","redux","redux-saga","redux-thunk","saga","side-effects","thunk"],"created_at":"2024-10-03T16:26:35.214Z","updated_at":"2025-05-07T10:35:43.468Z","avatar_url":"https://github.com/neurosnap.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# redux-cofx \n\n[![ci](https://github.com/neurosnap/redux-cofx/actions/workflows/test.yml/badge.svg)](https://github.com/neurosnap/redux-cofx/actions/workflows/test.yml)\n\nRedux middleware: Sagas as thunks; `redux-saga` meets `redux-thunk`\n\nMiddleware for `redux` that allows developers to dispatch actions which trigger\ngenerator functions. On top of that, these generator functions have an API\nfor describing side-effect as opposed to activating them. Let `redux-cofx` handle\nthe side-effects, all you need to worry about is describing how the side-effects\nshould work.\n\n## Features\n\n- Action creators spawning side-effects\n- Want to describe side-effects as data\n- Testing is incredibly simple\n- Similar API as `redux-saga` (select, put, take, call, fork, spawn, all, delay)\n- Typescript support\n- Upgradability from [react-cofx](https://github.com/neurosnap/react-cofx) and to [redux-saga](https://github.com/redux-saga/redux-saga)\n\n## Install\n\n```bash\nyarn add redux-cofx\n```\n\n## Usage\n\n```js\nimport cofxMiddleware, { createEffect, call, select, put } from \"redux-cofx\";\nimport { applyMiddleware, createStore } from \"redux\";\n\nconst reducer = (state) =\u003e state;\nconst store = createStore(reducer, applyMiddleware(cofxMiddleware));\n\n// action creators\nconst todosSuccess = payload =\u003e ({\n  type: \"TODO_SUCCESS\",\n  payload\n});\nconst uploadTodos = todos =\u003e createEffect(effect, todos);\n\n// selector\nconst getApiToken = state =\u003e state.token;\n\n// effect\nfunction* effect(todos) {\n  const token = yield select(getApiToken);\n\n  const result = yield call(fetch, \"/todos\", {\n    method: \"POST\",\n    headers: {\n      Authorization: `Bearer ${token}`\n    },\n    body: JSON.stringify(todos)\n  });\n  const json = yield call([result, \"json\"]);\n\n  yield put(todosSuccess(json));\n}\n\nconst todos = [\"drop kids off at the pool\", \"make dinner\"];\n// trigger effect\nstore.dispatch(uploadTodos(todos));\n```\n\nUsing `enableBatching` we also provide the ability to batch multiple actions\nwhile only triggering one state change.  See the API section for more info.\n\n## Testing\n\nSee [cofx](https://github.com/neurosnap/cofx#testing) for instructions on\nhow to test an effect function.\n\n## API\n\nFor `cofx` specific effects (e.g. call, fork, spawn, delay, all), see [cofx docs](https://github.com/neurosnap/cofx)\n\n### select\n\nAccepts a function with state as the parameter\n\n```js\nconst getToken = (state) =\u003e {\n  return state.token;\n}\n\nfunction* effect() {\n  const token = yield select(getToken);\n}\n```\n\n### put\n\nalias for `store.dispatch`\n\n```js\nconst setToken = (payload) =\u003e {\n  return {\n    type: 'SET_TOKEN',\n    payload,\n  }\n};\n\nfunction* effect() {\n  yield put(setToken('1234'));\n}\n```\n\n### batch (requires enableBatching, added v2.0)\n\ndispatch multiple actions with only a single state update.\nThis effect takes an array of actions and dispatches them all within a\nsingle state update.  This is useful if there are multiple actions being dispatched in sequence\nand you don't want to re-render the view all of those times.\n\n```js\nimport { batch } from 'redux-cofx';\n\nconst setToken = (payload) =\u003e {\n  return {\n    type: 'SET_TOKEN',\n    payload,\n  }\n};\nconst login = () =\u003e {\n  return {\n    type: 'LOGIN',\n  };\n}\n\nfunction* effect() {\n  yield batch([\n    setToken('1234'),\n    login(),\n  ]); // this will only trigger one state update and only one re-render of react!\n}\n```\n\n### take\n\nWaits for the action to be dispatched\n\n```js\nfunction* effect() {\n  const action = yield take('SOMETHING');\n  console.log(action.payload);\n}\n\nconsole.log('output -\u003e');\nstore.dispatch({ type: 'SOMETHING', payload: 'nice!' });\n\n// output -\u003e\n// 'nice!'\n```\n\n## enableBatching (optional, added v2.0)\n\nThis is a higher order reducer that enables the use of `batch` which\nallows multiple actions to be dispatched with a single re-render.\n\n```js\nimport cofxMiddleware, { enabledBatching } from \"redux-cofx\";\nimport { applyMiddleware, createStore } from \"redux\";\n\nconst reducer = (state) =\u003e state;\nconst rootReducer = enableBatching(reducer);\nconst store = createStore(rootReducer, applyMiddleware(cofxMiddleware));\n```\n\n## batchActions (optional, added v2.3)\n\nThis is a simply action creator, when dispatched **outside** of an effect,\nwill dispatch all actions simultaneously updating redux store.\n\n```js\nimport cofxMiddleware, { enabledBatching, batchActions } from \"redux-cofx\";\nimport { applyMiddleware, createStore } from \"redux\";\n\nconst reducer = (state) =\u003e state;\nconst rootReducer = enableBatching(reducer);\nconst store = createStore(rootReducer, applyMiddleware(cofxMiddleware));\n\nstore.dispatch(\n  batchActions([\n    { type: 'SOMETHING', payload: 'great' },\n    { type: 'DO_I', payload: 'exist?' },\n  ])\n);\n```\n\n### createEffect\n\nThis function creates an effect action that you would dispatch with redux.\n\n```js\nimport { put, createEffect } from 'redux-cofx';\n\nfunction* effOne(payload: any) {\n  // payload === 'ok'\n  yield put({ type: 'AWESOME', payload });\n}\n\nconst one = (payload: any) =\u003e createEffect(effOne, payload);\nstore.dispatch(one('ok'));\n```\n\n#### cancel an effect (added v2.0)\n\nWe also provide the ability to cancel an effect.  The cancel *must* be a promise.\nWhen the cancel promise is `resolve`d then it will cancel the effect.\n\n```js\nimport { put, createEffect } from 'redux-cofx';\n\nfunction* effOne(payload: any) {\n  yield delay(1000); // delay for 1 second\n  yield put({ type: 'AWESOME', payload }); // payload === 'ok'\n}\n\nconst cancel = () =\u003e new Promise((resolve) =\u003e {\n  setTimeout(() =\u003e {\n    resolve();\n  }, 500);\n});\nconst one = (payload: any) =\u003e createEffect({\n  fn: effOne,\n  args: [payload],\n  cancel,\n});\nstore.dispatch(one('ok'));\n// the effect will be cancelled before the action can be dispatched!\n```\n\n### createEffects\n\nThis is a helper function to create effects based on a map of effect names to effect function.\nThe created effects will accept a payload and send it as a parameter to the effect function.\n\n```js\nimport { put, createEffects } from 'redux-cofx';\n\nfunction* effOne(payload: any) {\n  // payload === 'ok'\n  yield put({ type: 'AWESOME', payload });\n}\n\nfunction* effTwo(payload: any) {\n  // payload === 'nice'\n  yield put({ type: 'WOW', payload });\n}\n\nconst effects = createEffects({\n  one: effOne,\n  two: effTwo,\n});\n\nstore.dispatch(effects.one('ok'));\nstore.dispatch(effects.two('nice'));\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneurosnap%2Fredux-cofx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneurosnap%2Fredux-cofx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneurosnap%2Fredux-cofx/lists"}