{"id":13394486,"url":"https://github.com/jeffbski/redux-logic","last_synced_at":"2025-05-14T10:05:20.071Z","repository":{"id":10160465,"uuid":"64698277","full_name":"jeffbski/redux-logic","owner":"jeffbski","description":"Redux middleware for organizing all your business logic. Intercept actions and perform async processing.","archived":false,"fork":false,"pushed_at":"2024-08-31T00:23:01.000Z","size":2110,"stargazers_count":1806,"open_issues_count":62,"forks_count":107,"subscribers_count":39,"default_branch":"master","last_synced_at":"2024-12-20T09:30:05.429Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/jeffbski.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-08-01T20:12:23.000Z","updated_at":"2024-11-28T16:32:50.000Z","dependencies_parsed_at":"2024-11-16T03:28:21.323Z","dependency_job_id":null,"html_url":"https://github.com/jeffbski/redux-logic","commit_stats":{"total_commits":463,"total_committers":25,"mean_commits":18.52,"dds":0.08207343412527002,"last_synced_commit":"3ffb04aac38466c27813071fb5f6762af86e8500"},"previous_names":[],"tags_count":85,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffbski%2Fredux-logic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffbski%2Fredux-logic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffbski%2Fredux-logic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeffbski%2Fredux-logic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jeffbski","download_url":"https://codeload.github.com/jeffbski/redux-logic/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247953924,"owners_count":21024118,"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-07-30T17:01:21.323Z","updated_at":"2025-04-09T01:23:14.274Z","avatar_url":"https://github.com/jeffbski.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","Utilities","目录"],"sub_categories":["Side Effects","\u003ca id=\"state\"\u003e状态管理\u003c/a\u003e"],"readme":"# redux-logic\n\n\u003e \"One place for all your business logic and action side effects\"\n\nRedux middleware that can:\n\n- **intercept** (validate/transform/augment) actions AND\n- **perform async processing** (fetching, I/O, side effects)\n\n[![Build Status](https://secure.travis-ci.org/jeffbski/redux-logic.png?branch=master)](http://travis-ci.org/jeffbski/redux-logic) [![Known Vulnerabilities](https://snyk.io/test/github/jeffbski/redux-logic/badge.svg)](https://snyk.io/test/github/jeffbski/redux-logic) [![NPM Version Badge](https://img.shields.io/npm/v/redux-logic.svg)](https://www.npmjs.com/package/redux-logic)\n\n## tl;dr\n\nWith redux-logic, you have the **freedom** to write your logic in **your favorite JS style**:\n\n- plain **callback** code - `dispatch(resultAction)`\n- **promises** - `return axios.get(url).then(...)`\n- **async/await** - `result = await fetch(url)`\n- **observables** - `ob$.next(action1)`\n\n\u003e Use the type of code you and your team are comfortable and experienced with.\n\nLeverage powerful **declarative** features by simply setting properties:\n\n- **filtering** for action type(s) or with regular expression(s)\n- **cancellation** on receiving action type(s)\n- use only response for the **latest** request\n- **debouncing**\\\n- **throttling**\n- dispatch actions - auto **decoration** of payloads\n\nTesting your logic is straight forward and simple. [redux-logic-test](https://github.com/jeffbski/redux-logic-test) provides additional utilities to make testing a breeze.\n\nWith simple code your logic can:\n\n- **intercept** actions before they hit the reducer\n  - **validate**, verify, auth check actions and allow/reject or modify actions\n  - **transform** - augment/enhance/modify actions\n- **process** - **async processing** and dispatching, orchestration, I/O (ajax, REST, subscriptions, GraphQL, web sockets, ...)\n\nRedux-logic makes it easy to use code that is split into bundles, so you can dynamically load logic right along with your split UI.\n\nServer rendering is simplified with redux-logic since it lets you know when all your async fetching is complete without manual tracking.\n\nInspired by redux-observable epics, redux-saga, and custom redux middleware, redux-logic combines ideas of each into a simple easy to use API.\n\n## Quick Example\n\nThis is an example of logic which will listen for actions of type FETCH_POLLS and it will perform ajax request to fetch data for which it dispatches the results (or error) on completion. It supports cancellation by allowing anything to send an action of type CANCEL_FETCH_POLLS. It also uses `take latest` feature that if additional FETCH_POLLS actions come in before this completes, it will ignore the outdated requests.\n\nThe developer can just declare the type filtering, cancellation, and take latest behavior, no code needs to be written for that. That leaves the developer to focus on the real business requirements which are invoked in the process hook.\n\n```js\nimport { createLogic } from 'redux-logic';\n\nconst fetchPollsLogic = createLogic({\n  // declarative built-in functionality wraps your code\n  type: FETCH_POLLS, // only apply this logic to this type\n  cancelType: CANCEL_FETCH_POLLS, // cancel on this type\n  latest: true, // only take latest\n\n  // your code here, hook into one or more of these execution\n  // phases: validate, transform, and/or process\n  process({ getState, action }, dispatch, done) {\n    axios\n      .get('https://survey.codewinds.com/polls')\n      .then((resp) =\u003e resp.data.polls)\n      .then((polls) =\u003e dispatch({ type: FETCH_POLLS_SUCCESS, payload: polls }))\n      .catch((err) =\u003e {\n        console.error(err); // log since could be render err\n        dispatch({ type: FETCH_POLLS_FAILED, payload: err, error: true });\n      })\n      .then(() =\u003e done()); // call done when finished dispatching\n  }\n});\n```\n\nSince redux-logic gives you the freedom to use your favorite style of JS code (callbacks, promises, async/await, observables), it supports many features to make that easier, [explained in more detail](./docs/api.md#dispatch---multi-dispatching-and-process-variable-signature)\n\n## Table of contents\n\n- \u003ca href=\"#updates\"\u003eUpdates\u003c/a\u003e\n- \u003ca href=\"#goals\"\u003eGoals\u003c/a\u003e\n- \u003ca href=\"#usage\"\u003eUsage\u003c/a\u003e\n- \u003ca href=\"./docs/api.md\"\u003eFull API\u003c/a\u003e\n- \u003ca href=\"#examples\"\u003eExamples\u003c/a\u003e - [Live](#live-examples) and [full examples](#full-examples)\n- \u003ca href=\"#comparison-summaries\"\u003eComparison summaries\u003c/a\u003e to \u003ca href=\"#compared-to-fat-action-creators\"\u003efat action creators\u003c/a\u003e, \u003ca href=\"#compared-to-redux-thunk\"\u003ethunks\u003c/a\u003e, \u003ca href=\"#compared-to-redux-observable\"\u003eredux-observable\u003c/a\u003e, \u003ca href=\"#compared-to-redux-saga\"\u003eredux-saga\u003c/a\u003e, \u003ca href=\"#compared-to-custom-redux-middleware\"\u003ecustom middleware\u003c/a\u003e\n- \u003ca href=\"#implementing-sampal-pattern\"\u003eSAM/PAL pattern\u003c/a\u003e\n- \u003ca href=\"#other\"\u003eOther\u003c/a\u003e - todo, inspiration, license\n\n## Updates\n\nFull release notes of breaking and notable changes are available in [releases](https://github.com/jeffbski/redux-logic/releases). This project follows semantic versioning.\n\nA few recent changes that are noteworthy:\n\n### v2.0.0\n\nUpdated to RxJS@6. Your logic code can continue to use RxJS@5 until\nyou are ready to upgrade to 6.\n\nOptimizations to reduce the stack used, especially if a subset of\nfeatures is used.\n\n### v1.0.0\n\nTranspilation switched to Babel 7 and Webpack 4\n\n### v0.12\n\nThese changes are not breaking but they are noteworthy since they prepare for the next version which will be breaking mainly to remove the single dispatch version of process hook which has been a source of confusion.\n\n- Single dispatch signature for `process` hook is deprecated and warns in development build. This is when you use the signature `process(deps, dispatch)` (including dispatch but not done). To migrate change your use to include done `process(deps, dispatch, done)` and call the `done` cb when done dispatching.\n- New option `warnTimeout` defaults to 60000 (ms == one minute) which warns (in development build only) when the logic exceeds the specified time without completion. Adjust this value or set it to 0 if you have logic that needs to exceed this time or purposefully never ends (like listening to a web socket)\n\n## Goals\n\n- organize business logic keeping action creators and reducers clean\n  - action creators are light and just post action objects\n  - reducers just focus on updating state\n  - intercept and perform validations, verifications, authentication\n  - intercept and transform actions\n  - perform async processing, orchestration, dispatch actions\n- wrap your core business logic code with declarative behavior\n  - filtered - apply to one or many action types or even all actions\n  - cancellable - async work can be cancelled\n  - limiting (like taking only the latest, throttling, and debouncing)\n- features to support business logic and large apps\n  - have access to full state to make decisions\n  - easily composable to support large applications\n  - inject dependencies into your logic, so you have everything needed in your logic code\n  - dynamic loading of logic for splitting bundles in your app\n  - your core logic code stays focussed and simple, don't use generators or observables unless you want to.\n  - create subscriptions - streaming updates\n  - easy testing - since your code is just a function it's easy to isolate and test\n\n## Usage\n\nredux-logic uses rxjs@6 under the covers and to prevent multiple copies (of different versions) from being installed, it is recommended to install rxjs first before redux-logic. That way you can use the same copy of rxjs elsewhere.\n\nIf you are never using rxjs outside of redux-logic and don't plan to use Observables directly in your logic then you can skip the rxjs install and it will be installed as a redux-logic dependency. However if you think you might use Observables directly in the future (possibly creating Observables in your logic), it is still recommended to install rxjs separately first\njust to help ensure that only one copy will be in the project.\n\nThe rxjs install below `npm install rxjs@^6` installs the lastest 6.x.x version of rxjs.\n\n```bash\nnpm install rxjs@^6 --save  # optional see note above\nnpm install redux-logic --save\n```\n\n```js\n// in configureStore.js\nimport { createLogicMiddleware } from 'redux-logic';\nimport rootReducer from './rootReducer';\nimport arrLogic from './logic';\n\nconst deps = { // optional injected dependencies for logic\n  // anything you need to have available in your logic\n  A_SECRET_KEY: 'dsfjsdkfjsdlfjls',\n  firebase: firebaseInstance\n};\n\nconst logicMiddleware = createLogicMiddleware(arrLogic, deps);\n\nconst middleware = applyMiddleware(\n  logicMiddleware\n);\n\nconst enhancer = middleware; // could compose in dev tools too\n\nexport default function configureStore() {\n  const store = createStore(rootReducer, enhancer);\n  return store;\n}\n\n\n// in logic.js - combines logic from across many files, just\n// a simple array of logic to be used for this app\nexport default [\n ...todoLogic,\n ...pollsLogic\n];\n\n\n// in polls/logic.js\nimport { createLogic } from 'redux-logic';\n\nconst validationLogic = createLogic({\n  type: ADD_USER,\n  validate({ getState, action }, allow, reject) {\n    const user = action.payload;\n    if (!getState().users[user.id]) { // can also hit server to check\n      allow(action);\n    } else {\n      reject({ type: USER_EXISTS_ERROR, payload: user, error: true })\n    }\n  }\n});\n\nconst addUniqueId = createLogic({\n  type: '*',\n  transform({ getState, action }, next) {\n    // add unique tid to action.meta of every action\n    const existingMeta = action.meta || {};\n    const meta = {\n      ...existingMeta,\n      tid: shortid.generate()\n    },\n    next({\n      ...action,\n      meta\n    });\n  }\n});\n\nconst fetchPollsLogic = createLogic({\n  type: FETCH_POLLS, // only apply this logic to this type\n  cancelType: CANCEL_FETCH_POLLS, // cancel on this type\n  latest: true, // only take latest\n  process({ getState, action }, dispatch, done) {\n    axios.get('https://survey.codewinds.com/polls')\n      .then(resp =\u003e resp.data.polls)\n      .then(polls =\u003e dispatch({ type: FETCH_POLLS_SUCCESS,\n                                payload: polls }))\n      .catch(err =\u003e {\n             console.error(err); // log since could be render err\n             dispatch({ type: FETCH_POLLS_FAILED, payload: err,\n                        error: true })\n      })\n      .then(() =\u003e done());\n  }\n});\n\n// pollsLogic\nexport default [\n  validationLogic,\n  addUniqueId,\n  fetchPollsLogic\n];\n\n```\n\n### processOptions introduced for redux-logic@0.8.2 allowing for even more streamlined code\n\n`processOptions` has these new properties which affect the process hook behavior:\n\n- `dispatchReturn` - the returned value of the process function will be dispatched or if it is a promise or observable then the resolve, reject, or observable values will be dispatched applying any successType or failType logic if defined. Default is determined by arity of process fn, `true` if dispatch not provided, `false` otherwise. [Details](https://github.com/jeffbski/redux-logic/blob/master/docs/api.md#dispatch---multi-dispatching-and-process-variable-signature)\n\n- `successType` - dispatch this action type using contents of dispatch as the payload (also would work with with promise or observable). You may alternatively provide an action creator function to use instead and it will receive the value as only parameter. Default: `undefined`.\n\n  - if successType is a string action type\n\n    - create action using successType and provide value as payload. ex: with `successType:'FOO'`, result would be `{ type: 'FOO', payload: value }`\n\n  - if successType is an action creator fn receiving the value as only parameter\n    - use the return value from the action creator fn for dispatching ex: `successType: x =\u003e ({ type: 'FOO', payload: x })`\n    - if the action creator fn returns a falsey value like `undefined` then nothing will be dispatched. This allows your action creator to control whether something is actually dispatched based on the value provided to it.\n\n- `failType` - dispatch this action type using contents of error as the payload, sets error: true (would also work for rejects of promises or error from observable). You may alternatively provide an action creator function to use instead which will receive the error as the only parameter. Default: `undefined`.\n\n  - if failType is a string action type\n\n    - create action using failType, provide value as the payload, and set error to true. ex: with `failType:'BAR'`, result would be `{ type: 'BAR', payload: errorValue, error: true }`\n\n  - if failType is an action creator function receiving the error value as its only parameter\n    - use the return value from the action creator fn for dispatching. ex: `failType: x =\u003e ({ type: 'BAR', payload: x, error: true })`\n    - if the action creator fn returns a falsey value like `undefined` then nothing will be dispatched. This allows your action creator to control whether something is actually dispatched based on the value provided to it.\n\nThe successType and failType would enable clean code, where you can simply return a promise or observable that resolves to the payload and rejects on error. The resulting code doesn't have to deal with dispatch and actions directly.\n\n```js\nimport { createLogic } from 'redux-logic';\n\nconst fetchPollsLogic = createLogic({\n  // declarative built-in functionality wraps your code\n  type: FETCH_POLLS, // only apply this logic to this type\n  cancelType: CANCEL_FETCH_POLLS, // cancel on this type\n  latest: true, // only take latest\n\n  processOptions: {\n    // optional since the default is true when dispatch is omitted from\n    // the process fn signature\n    dispatchReturn: true, // use returned/resolved value(s) for dispatching\n    // provide action types or action creator functions to be used\n    // with the resolved/rejected values from promise/observable returned\n    successType: FETCH_POLLS_SUCCESS, // dispatch this success act type\n    failType: FETCH_POLLS_FAILED // dispatch this failed action type\n  },\n\n  // Omitting dispatch from the signature below makes the default for\n  // dispatchReturn true allowing you to simply return obj, promise, obs\n  // not needing to use dispatch directly\n  process({ getState, action }) {\n    return axios.get('https://survey.codewinds.com/polls').then((resp) =\u003e resp.data.polls);\n  }\n});\n```\n\nThis is pretty nice leaving us with mainly our business logic code that could be easily extracted and called from here.\n\n## Full API\n\nSee the [docs for the full api](./docs/api.md)\n\n## Examples\n\n### Live examples\n\n- [search async axios fetch](https://codesandbox.io/s/6zv883qnqk) - live search using debounce and take latest functionality with axios fetch\n- [search rxjs ajax fetch](https://codesandbox.io/s/rm16mzz94n) - live search using debounce and take latest functionality with rxjs ajax fetch\n- [search rxjs ajax fetch - using processOptions](https://codesandbox.io/s/lyw0225pr9) - live search using debounce and take latest with rxjs ajax fetch using processOptions to streamline the code, user logic using rxjs@5\n- [search rxjs6 ajax fetch - using processOptions](https://codesandbox.io/s/q7oo6wo2n6) - live search using debounce and take latest with rxjs ajax fetch using processOptions to streamline the code, user logic using rxjs@6\n- [async axios fetch - single page](https://codesandbox.io/s/82xjxx3kp2) - displayed using React\n- [async rxjs-ajax fetch](https://codesandbox.io/s/1o14zmz4rq) - async fetching using RxJS ajax which supports XHR abort for cancels\n- [async axios fetch - single page redux only](https://codesandbox.io/s/2w1lkpq19p) - just the redux and redux-logic code\n- [async axios fetch - using processOptions](https://codesandbox.io/s/4w6r5mvxqx) - using processOptions to streamline your code further with React\n- [async rxjs-ajax fetch - using processOptions](https://codesandbox.io/s/o45z24rpky) - async fetch using RxJS ajax (supporting XHR abort on cancel) and processOptions for clean code.\n- [async await - react](https://codesandbox.io/s/0q0xw8vm6n) - using ES7 async functions (async/await) displaying with React\n- [async await - redux only](https://codesandbox.io/s/742zx6w946) - using ES7 async functions (async/await) - just redux and redux-logic code\n- [async await - react processOptions](https://codesandbox.io/s/64l8xv1po3) - using ES7 async functions (async/await) with processOptions, displayed with React\n- [drag and drop - rxjs@6 - react](https://codesandbox.io/s/n34x5j3jv4) - drag a button using rxjs@6 and the new stream added to redux-logic@v2 `action$`\n- [websockets - rxjs@6 - react](https://codesandbox.io/s/m38l7n745y) - websocket send and receive using rxjs@6 and react\n\n### Full examples\n\nhttps://github.com/jeffbski/redux-logic-examples/tree/master/examples/search-async-fetch\n\n- [search-async-fetch](https://github.com/jeffbski/redux-logic-examples/tree/master/examples/search-async-fetch) - search async fetch example using axios uses debouncing and take latest features\n- [async-fetch-vanilla](https://github.com/jeffbski/redux-logic-examples/tree/master/examples/async-fetch-vanilla) - async fetch example using axios\n- [async-rxjs-ajax-fetch](https://github.com/jeffbski/redux-logic-examples/tree/master/examples/async-rxjs-ajax-fetch) - async fetch example using RxJS ajax (supporting XHR abort on cancel) and redux-actions\n- [async-fetch-proc-options](https://github.com/jeffbski/redux-logic-examples/tree/master/examples/async-fetch-proc-options) - async fetch example using axios and the new processOptions feature\n- [async-rxjs-ajax-proc-options](https://github.com/jeffbski/redux-logic-examples/tree/master/examples/async-rxjs-ajax-proc-options) - async RxJS ajax (with XHR abort on cancel) fetch example using axios and the new processOptions feature\n- [async-await - ES7 async functions](https://github.com/jeffbski/redux-logic-examples/tree/master/examples/async-await) - async fetch example using axios and ES7 async functions (async/await)\n- [async-await - ES7 async functions with processOptions](https://github.com/jeffbski/redux-logic-examples/tree/master/examples/async-await-proc-options) - async fetch example using axios and ES7 async functions (async/await) and using the new processOptions feature\n- [countdown](https://github.com/jeffbski/redux-logic-examples/tree/master/examples/countdown) - a countdown timer implemented with setInterval\n- [countdown-obs](https://github.com/jeffbski/redux-logic-examples/tree/master/examples/countdown-obs) - a countdown timer implemented with Rx.Observable.interval\n- [form-validation](https://github.com/jeffbski/redux-logic-examples/tree/master/examples/form-validation) - form validation and async post to server using axios, displays updated user list\n- [notification](https://github.com/jeffbski/redux-logic-examples/tree/master/examples/notification) - notification message example showing at most N messages for X amount of time, rotating queued messages in as others expire\n- [search-single-file](https://github.com/jeffbski/redux-logic-examples/tree/master/examples/single-file) - search async fetch example with all code in a single file and displayed with React\n- [single-file-redux](https://github.com/jeffbski/redux-logic-examples/tree/master/examples/single-file-redux) - async fetch example with all code in a single file and appended to the container div. Only redux and redux-logic code.\n\n## Comparison summaries\n\nFollowing are just short summaries to compare redux-logic to other approaches.\n\nFor a more detailed comparison with examples, see by article in docs, [Where do I put my business logic in a React-Redux application?](./docs/where-business-logic.md).\n\n### Compared to fat action creators\n\n- no easy way to cancel or do limiting like take latest with fat action creators\n- action creators would not have access to the full global state so you might have to pass down lots of extra data that isn't needed for rendering. Every time business logic changes might require new data to be made available\n- no global interception using just action creators - applying logic or transformations across all or many actions\n- Testing components and fat action creators may require running the code (possibly mocked API calls).\n\n### Compared to redux-thunk\n\n- With thunks business logic is spread over action creators\n- With thunks there is not an easy way to cancel async work nor to perform (take latest) limiting\n- no global interception with thunks - applying logic or transformations across all or many actions\n- Testing components and thunked action creators may require running the code (possibly mocked API calls). When you have a thunk (function or promise) you don't know what it does unless you execute it.\n\n### Compared to redux-observable\n\n- redux-logic doesn't require the developer to use rxjs observables. It uses observables under the covers to provide cancellation, throttling, etc. You simply configure these parameters to get this functionality. You can still use rxjs in your code if you want, but not a requirement.\n- redux-logic hooks in before the reducer stack like middleware allowing validation, verification, auth, transformations. Allow, reject, transform actions before they hit your reducers to update your state as well as accessing state after reducers have run. redux-observable hooks in after the reducers have updated state so they have no opportunity to prevent the updates.\n\n### Compared to redux-saga\n\n- redux-logic doesn't require you to code with generators\n- redux-saga relies on pulling data (usually in a never ending loop) while redux-logic and logic are reactive, responding to data as it is available\n- redux-saga runs after reducers have been run, redux-logic can intercept and allow/reject/modify before reducers run also as well as after\n\n### Compared to custom redux middleware\n\n- Both are fully featured to do any type of business logic (validations, transformations, processing)\n- redux-logic already has built-in capabilities for some of the hard stuff like cancellation, limiting, dynamic loading of code. With custom middleware you have to implement all functionality.\n- No safety net, if things break it could stop all of your future actions\n- Testing requires some mocking or setup\n\n### Implementing SAM/PAL Pattern\n\nThe [SAM (State-Action-Model) pattern](http://sam.js.org) is a pattern introduced by Jean-Jacques Dubray. Also known as the PAL (proposer, acceptor, learner) pattern based on Paxos terminology.\n\nA few of the challenging parts of implementing this with a React-Redux application are:\n\n1.  where to perform the `accept` (interception) of the proposed action performing validation, verification, authentication against the current model state. Based on the current state, it might be appropriate to modify the action, dispatch a different action, or simply suppress the action.\n2.  how to trigger actions based on the state after the model has finished updating, referred to as the `NAP` (next-action-predicate).\n\nCustom Redux middleware can be introduced to perform this logic, but you'll be implementing most everything on your own.\n\nWith `redux-logic` you can implement the SAM / PAL pattern easily in your React/Redux apps.\n\nNamely you can separate out your business logic from your action creators and reducers keeping them thin. redux-logic provides a nice place to accept, reject, and transform actions before your reducers are run. You have access to the full state to make decisions and you can trigger actions based on the updated state as well.\n\nSolving those SAM challenges previously identified using redux-logic:\n\n1.  perform acceptance in redux-logic `validate` hooks, you have access to the full state (model) of the app to make decisions. You can perform synchronous or asynchronous logic to determine whether to accept the action and you may augment, modify, substitute actions, or suppress as desired.\n2.  Perform NAP processing in redux-logic `process` hooks. The process hook runs after the actions have been sent down to the reducers so you have access to the full model (state) after the updates where you can make decisions and dispatch additional actions based on the updated state.\n\n\u003ca name=\"other\"\u003e\u003c/a\u003e\n\n## Inspiration\n\nredux-logic was inspired from these projects:\n\n- [redux-observable epics](https://redux-observable.js.org)\n- [redux-saga](http://yelouafi.github.io/redux-saga/)\n- [redux middleware](http://redux.js.org/docs/advanced/Middleware.html)\n\n## Minimized/gzipped size with all deps\n\n(redux-logic only includes the modules of RxJS 6 that it uses)\n\n```\nredux-logic.min.js.gz 18KB\n```\n\nNote: If you are already including RxJS 6 into your project then the resulting delta will be much smaller.\n\n## TODO\n\n- more docs\n- more examples\n\n## Get involved\n\nIf you have input or ideas or would like to get involved, you may:\n\n- contact me via twitter @jeffbski - \u003chttp://twitter.com/jeffbski\u003e\n- open an issue on github to begin a discussion - \u003chttps://github.com/jeffbski/redux-logic/issues\u003e\n- fork the repo and send a pull request (ideally with tests) - \u003chttps://github.com/jeffbski/redux-logic\u003e\n- See the [contributing guide](http://github.com/jeffbski/redux-logic/raw/master/CONTRIBUTING.md)\n\n## Supporters\n\nThis project is supported by [CodeWinds Training](https://codewinds.com/)\n\n\u003ca name=\"license\"/\u003e\n\n## License - MIT\n\n- [MIT license](http://github.com/jeffbski/redux-logic/raw/master/LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeffbski%2Fredux-logic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjeffbski%2Fredux-logic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeffbski%2Fredux-logic/lists"}