{"id":13793447,"url":"https://github.com/redux-effects/redux-effects","last_synced_at":"2026-01-31T04:35:25.130Z","repository":{"id":57350610,"uuid":"41266043","full_name":"redux-effects/redux-effects","owner":"redux-effects","description":null,"archived":false,"fork":false,"pushed_at":"2017-02-01T13:25:08.000Z","size":35,"stargazers_count":495,"open_issues_count":5,"forks_count":9,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-10-14T08:42:48.966Z","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":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/redux-effects.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-08-23T20:30:12.000Z","updated_at":"2024-10-21T23:54:57.000Z","dependencies_parsed_at":"2022-09-15T01:44:51.962Z","dependency_job_id":null,"html_url":"https://github.com/redux-effects/redux-effects","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/redux-effects/redux-effects","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redux-effects%2Fredux-effects","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redux-effects%2Fredux-effects/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redux-effects%2Fredux-effects/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redux-effects%2Fredux-effects/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/redux-effects","download_url":"https://codeload.github.com/redux-effects/redux-effects/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redux-effects%2Fredux-effects/sbom","scorecard":{"id":768203,"data":{"date":"2025-08-11","repo":{"name":"github.com/redux-effects/redux-effects","commit":"aa2631273c39f1ff69c73695b74653742cd58207"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 1/27 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 4 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-23T01:28:21.371Z","repository_id":57350610,"created_at":"2025-08-23T01:28:21.371Z","updated_at":"2025-08-23T01:28:21.371Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28929701,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-31T04:05:25.756Z","status":"ssl_error","status_checked_at":"2026-01-31T04:02:35.005Z","response_time":128,"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":[],"created_at":"2024-08-03T23:00:21.481Z","updated_at":"2026-01-31T04:35:25.100Z","avatar_url":"https://github.com/redux-effects.png","language":"JavaScript","funding_links":[],"categories":["Utilities","JavaScript","目录"],"sub_categories":["Side Effects","\u003ca id=\"state\"\u003e状态管理\u003c/a\u003e"],"readme":"# redux-effects\n\nVirtual DOM for effects and impurities.  You write pure functions, redux-effects handles the rest.\n\n## Installation\n\n`npm install redux-effects`\n\n## Benefits\n\n  * Trivial universality.  If your effect middleware is universal, your app is universal.\n  * [Powerful meta-programming facilities](#metaprogramming) (e.g. request caching)\n  * More testable code\n  * Better insights into what is happening in your application (e.g. logging effects)\n  * Better ability to serialize state\n\n## Usage\n\nAdd redux-effects anywhere in your redux middleware stack*:\n\n```javascript\nimport effects from 'redux-effects'\nimport fetch from 'redux-effects-fetch'\nimport cookie from 'redux-effects-cookie'\nimport location from 'redux-effects-location'\n\napplyMiddleware(effects, fetch, cookie, location)\n```\n\n_* It used to need to come first, but that is no longer the case_\n\n### In action creators\n\nAll effectful action creators should return a declarative object describing the effect to be done, even if their operation is normally synchronous*.  In order to operate on the values returned by these actions, you need to specify your handlers in `.meta.steps` in the action object.  This library comes with a composition utility `bind`, but you are free to write your own such as [declarative-promise](https://github.com/redux-effects/declarative-promise).\n\n**E.g. Math.random or accessing cookies.  These values are also impure, even though they are synchronous, because they are non-deterministic with respect to your function's parameters.*\n\n```javascript\nimport {bind} from 'redux-effects'\nimport {cookie} from 'redux-effects-cookie'\nimport {createAction} from 'redux-actions'\n\nfunction checkAuth () {\n  return bind(cookie('authToken'), setAuthToken)\n}\n\nconst setAuthToken = createAction('SET_AUTH_TOKEN')\n```\n\nThe values returned by your actions will be passed to the handlers specified on your action object.  Then, what your handlers return will be dispatched back into redux to either trigger other effects or be preserved in state.  If your functions do not return a value, they do not do anything.  Their only ability to effect the world is by ultimately dispatching actions that trigger state reducers, or by triggering effects that cause state to be preserved elsewhere (e.g. a POST request to an API server).\n\n### Effect composition\n\nEffects compose by placing `steps` in `.meta.steps` on the action object.  E.g.\n\n```javascript\n{\n  type: 'EFFECT_COMPOSE',\n  payload: {\n    type: 'FETCH'\n    payload: {url: '/some/thing', method: 'GET'}\n  },\n  meta: {\n    steps: [\n      [success, failure]\n    ]\n  }\n}\n```\n\nSince this is cumbersome to write out, there are libraries / action creators to help with it:\n\n  * `bind` which comes bundled with redux-effects\n  * [declarative-promise](https://github.com/redux-effects/declarative-promise)\n\nBut it is important to understand that ultimately these libraries just produce plain JS objects, and you are totally free to create your own composition interfaces that behave exactly the way you want if you don't like these.  There is nothing magical going on.\n\n## Writing effectful middleware\n\nEffects middleware look essentially just like regular redux middleware, except that it _*must*_ return a promise.  If it does not return a promise, it won't compose with other effects, and so won't be very useful to anyone.\n\nAs a general rule, your effect middleware should be as dumb as possible.  There are two reasons for this:\n\n  * Effect middleware is inherently impure, and therefore difficult to test and reason about\n  * Keeping complexity out of the effect middleware ensures it is as generally useful as possible, and as open as possible to abstraction and metaprogramming.\n\n### Example - Simple cookie middleware\n\n```javascript\nimport cookie from 'component-cookie'\n\nexport default function ({dispatch, getState}) {\n  return next =\u003e action =\u003e {\n    if (action.type !== 'COOKIE') {\n      return next(action)\n    }\n\n    switch (action.verb) {\n      case 'set':\n        return Promise.resolve(cookie(action.name, action.value))\n      case 'get':\n        return Promise.resolve(cookie(action.name))\n    }\n  }\n}\n```\n\n### Example - Universal cookie middleware\n\n```javascript\nimport _cookie from 'component-cookie'\n\nexport default function (cookieMap) {\n  return ({dispatch, getState}) =\u003e next =\u003e action =\u003e {\n    if (action.type !== 'COOKIE') {\n      return next(action)\n    }\n\n    switch (action.verb) {\n      case 'set':\n        return Promise.resolve(cookie(action.name, action.value))\n      case 'get':\n        return Promise.resolve(cookie(action.name))\n    }\n  }\n\n  function cookie (name, value) {\n    if (arguments.length === 2) {\n      if (cookieMap) cookieMap[name] = value\n      else _cookie(name, value)\n    }\n\n    return cookieMap ? cookieMap[name] : _cookie(name)\n  }\n}\n```\n\nWith this form, you can simply initialize your cookie middleware with a map of cookies.  E.g.\n\n```javascript\nfunction (req, res, next) {\n  req.store = applyMiddleware(effects(cookie(req.cookies)))(createStore)\n}\n```\n\n## Metaprogramming\n\nWhere this approach gets really interesting is when you start applying transformations to your effects.  Normally these things are implemented in disparate and often hacky ways.  But when you have declarative descriptions of all of your effects, you can unify your transformations into your redux middleware stack, and they can be completely orthogonal to the actual implementations of the effects themselves.  Here are some examples:\n\n### Request caching\n\n```javascript\nfunction httpCache () {\n  const {get, set, check} = cache()\n\n  return next =\u003e action =\u003e\n   !isGetRequest(action)\n      ? next(action)\n      : check(action.payload.url)\n        ? Promise.resolve(get(action.payload.url))\n        : next(action).then(set(action.payload.url))\n}\n```\n\n### Response normalization\n\n```javascript\nfunction normalize () {\n  return next =\u003e action =\u003e\n    isGetRequest(action)\n      ? next(action).then(normalizr)\n      : next(action)\n}\n```\n\nNote that while these examples both transform http requests, they are completely orthogonal to the actual implementation of those requests, and completely orthogonal to the action creator interface you choose to use to generate your descriptors.  That means you can:\n\n  * Swap out your http request implementation\n  * Change your action creator interface\n  * Use a different effect composition strategy\n  * ...And most importantly, compose other transformations\n\nAnd not have to change your transform middleware at all.\n\n## Ecosystem\n\n### Effect drivers\n\nPlugins that enable various effects:\n\n  * [redux-effects-timeout](https://github.com/redux-effects/redux-effects-timeout) - setTimeout/setInterval/requestAnimationFrame\n  * [redux-effects-fetch](https://github.com/redux-effects/redux-effects-fetch) - HTTP Requests\n  * [redux-effects-cookie](https://github.com/redux-effects/redux-effects-cookie) - Cookie get/set\n  * [redux-effects-location](https://github.com/redux-effects/redux-effects-location) - Location (window.location) binding and setting\n  * [redux-effects-random](https://github.com/redux-effects/redux-effects-random) - Generate random numbers\n  * [redux-effects-events](https://github.com/redux-effects/redux-effects-events) - Dispatch actions in response to `window/document` events (e.g. `scroll/resize/popstate/etc`)\n  * [redux-effects-localstorage](https://github.com/redux-effects/redux-effects-localstorage) - localStorage effects driver\n  * [redux-effects-credentials](https://github.com/redux-effects/redux-effects-credentials) - Automatically decorate your fetch requests with credentials stored in state if the url matches a certain pattern.\n\n### Alternate composition middleware\n\n  * [redux-gen](https://github.com/weo-edu/redux-gen)\n\n### Composition helpers\n\n  * [declarative-promise](https://github.com/redux-effects/declarative-promise) - Wrap your actions in a promise-like interface\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredux-effects%2Fredux-effects","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredux-effects%2Fredux-effects","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredux-effects%2Fredux-effects/lists"}