{"id":18924639,"url":"https://github.com/dash-os/redux-saga-process","last_synced_at":"2026-03-15T20:37:54.225Z","repository":{"id":57158196,"uuid":"78564054","full_name":"Dash-OS/redux-saga-process","owner":"Dash-OS","description":"Encapsulated Logic \u0026 State Handling for Redux and Redux Saga","archived":false,"fork":false,"pushed_at":"2017-06-30T04:22:19.000Z","size":390,"stargazers_count":24,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-19T12:46:29.463Z","etag":null,"topics":["processes-reducers","react","reducer","redux","redux-saga","selector"],"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/Dash-OS.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":"2017-01-10T18:59:33.000Z","updated_at":"2024-11-18T22:37:30.000Z","dependencies_parsed_at":"2022-09-14T17:41:14.011Z","dependency_job_id":null,"html_url":"https://github.com/Dash-OS/redux-saga-process","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/Dash-OS%2Fredux-saga-process","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dash-OS%2Fredux-saga-process/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dash-OS%2Fredux-saga-process/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dash-OS%2Fredux-saga-process/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dash-OS","download_url":"https://codeload.github.com/Dash-OS/redux-saga-process/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dash-OS%2Fredux-saga-process/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259189674,"owners_count":22819092,"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":["processes-reducers","react","reducer","redux","redux-saga","selector"],"created_at":"2024-11-08T11:07:39.085Z","updated_at":"2026-03-15T20:37:54.153Z","avatar_url":"https://github.com/Dash-OS.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Redux Saga Process\n\n[![npm version](https://badge.fury.io/js/redux-saga-process.svg)](https://badge.fury.io/js/redux-saga-process)\n\nSaga Processes provide an encapsulated environment for processing complex (or simple) logic.\nThe Saga Process pattern that is being presenting is heavily inspired (surprisingly) by the general\nconcept of [processes](https://en.wikipedia.org/wiki/Process_(computing)).\n\nEach Process manages its logic, holds its local state, and makes intelligent decisions on when and how to dispatch a\npure repesentation of such data to the rest of the Application to be rendered efficiently. Keep\nthe logic out of your views.\n\n### Package Dependencies\n- [redux](https://github.com/reactjs/redux)\n- [redux-saga](https://github.com/redux-saga/redux-saga)\n- [reselect](https://github.com/reactjs/reselect)\n\n# Installation\n\n```bash\n$ yarn add redux-saga-process\n```\n**or**\n```bash\n$ npm install --save redux-saga-process\n```\n\n# Overview\n\nProcesses should remain a \"pure environment\" with a specific purpose or intent.  They\nrun as daemons in most cases which will live and respond throughout the lifetime of the\napplication.\n\nProcesses are run as sagas using the [redux-saga](https://github.com/redux-saga/redux-saga)\nlibrary.  They may also be configured to reduce a portion of your [redux](https://github.com/reactjs/redux)\nstore, providing a means for dispatching a pure representation of our data to be rendered by our\nview-layer.\n\n# Migrating to version \u003e 0.12\n\nNote that 0.12 no longer exports \"default\" and instead exports the named module \"Process\".\n\n```javascript\n// from\nimport Process from 'redux-saga-process'\n\n// to\nimport { Process } from 'redux-saga-process'\n```\n\n## Examples\n\nHere are a [few examples of some simple processes](https://github.com/Dash-OS/redux-saga-process/tree/master/examples) which are being used today.  When built\nproperly, a process should be a completely independent \"module\" which could be plugged\ninto any other app.  This should enable sharing of logic between your apps and/or each others.\n\n- [Network Monitor Process](https://github.com/Dash-OS/redux-saga-process/blob/master/examples/networkMonitor/networkMonitor.js) - this shows\n most of the options available in use.  We specify this as a client-rendered process only, reduce part of our store, and observer push-style\n events.  In use we do a bit more monitoring of different events, but stripped some of that out to make it more direct of an example.\n- [Action Logger](https://github.com/Dash-OS/redux-saga-process/blob/master/examples/actionLogger/actionLogger.js) - A minimal process which simply\n  logs any actions dispatched.\n- [Redux Persistor](https://github.com/Dash-OS/redux-saga-process/blob/master/examples/reduxPersistor/reduxPersistor.js) - Handles the management of\n  saving application data to persistent storage via [redux-persist](https://github.com/rt2zz/redux-persist) (in our case we use localForage).\n- [Firebase Listeners](https://github.com/Dash-OS/redux-saga-process/tree/master/examples/firebase) - Firebase Setup \u0026 Listeners\n\n***\n\n#### Creating a Saga Redux Process\n\n\n```javascript\nimport { Process } from 'redux-saga-process'\nclass MyProcess extends Process { /* ... */ }\n```\n\n***\n\n#### Building your Processes\n\nBefore we [create our Redux Store](http://redux.js.org/docs/basics/Store.html#store) we should start\nby building our processes.  During its build phase, the properties of each Process will be parsed and\nan environment will be created for each.\n\nBelow we show one example of how you may organize your processes.  We have a root\nfolder which has an index.js file that exports each \"category\" folder.  This folder\nthen exports each process that should be built.  With this setup, processes can be\nthought of as \"threads\" while each category folder would represent an overall process.\n\n```\n\u003e ./processes\n\u003e |---- ./ShoppingCart\n\u003e |-------- ./productFetcher\n\u003e |-------------- ./productFetcherProcess.js\n\u003e |-------- ./shoppingCart\n\u003e |-------------- ./shoppingCartProcess.js\n\u003e |-------- ./index.js\n\u003e |---- ./index.js\n```\n\n\u003e ***Note:*** When you build your processes, the library will search up to two levels deep for classes that can be\n\u003e built and build any discovered processes.\n\nGiven the above configuration, we would then build our processes easily enough.  We would\nsimply do the following:\n\n```javascript\n// configureStore.js\nimport { buildProcesses } from 'redux-saga-process'\nimport * as processCategories from '../processes'\nconst processes = buildProcesses(processCategories)\n```\n\n***\n\n#### Adding your Processes Reducers (Optional)\n\nWhen your Process defines the [static reducer](https://github.com/Dash-OS/redux-saga-process#static-reducer) property,\na redux-style reducer will be built and added to the list of reducers for you.  This is accomplished by\ncombining the reducers returned by ```buildProcesses``` (via Redux's [combineReducers](http://redux.js.org/docs/api/combineReducers.html)).  These\nreducers are found on the responses \"processReducers\" property.\n\n\u003e ***Tip:*** If multiple processes specify the same reducer name, they will be merged in the order they\n\u003e were created. This is handled by using the [arrayMapReducer](https://github.com/Dash-OS/redux-saga-process#arraymapreducerinitialstate-reducerarray-context) generator from [reducerGenerators.js](https://github.com/Dash-OS/redux-saga-process/blob/master/src/lib/reducerGenerators.js).\n\n```javascript\n// configureStore.js\nimport { combineReducers } from 'redux'\nimport { buildProcesses } from 'redux-saga-process'\nimport * as processCategories from '../processes'\nconst processes = buildProcesses(processCategories)\n\nconst rootReducer = combineReducers({\n  /* Any other reducers you have may be added */\n  ...processes.processReducers,\n})\n```\n\n***\n\n#### Running your Processes\n\nNow that we have built our processes we need to run them.  This is done from within your\n[root redux-saga](https://redux-saga.github.io/redux-saga/docs/introduction/BeginnerTutorial.html).\n\n```javascript\n// configureSagas.js\nimport { runProcesses } from 'redux-saga-process'\nimport * as processCategories from '../processes'\n\nfunction* root() {\n  // Processes are forked once ran, so we can simply use yield* in this case.\n  // You could also use fork if you wish - but be careful with [spawn] if you\n  // want to hot reload!\n  yield* runProcesses(processCategories)\n}\n\nexport default root\n```\n\n***\n\n#### Hot Reloading Processes\n\nWe have the ability to hot reload our processes.  RSP will pass the `state` object,\nif it exists, to the newly built process through the constructor.  This allows you to\nhandle it however you wish based on what the process does.\n\nThis allows us to hot reload the reducers **AND** the processes while maintaining state\nacross all of them.\n\n```js\n// when we run our sagas\nlet sagaTask = sagaMiddleware.run(rootSaga)\n// then...\nif ( module.hot ) {\n  module.hot.accept('./reducers', () =\u003e {\n    sagaTask.cancel()\n    sagaTask.done.then(() =\u003e {\n      // dynamic import reducers and sagas\n      Promise.all([\n        import('./reducers'),\n        import('../ui/shared/sagas')\n      ]).then( ([ new_reducers, new_sagas ]) =\u003e {\n        // replace the reducers with the new reducers - this will\n        // also rebuild our sagas efficiently (it doesnt re-build what it doesnt\n        // have to).\n        store.replaceReducer(new_reducers.default)\n        // Update our sagaTask with the new task and run our sagas\n        sagaTask = sagaMiddleware.run(new_sagas.default)\n        // in case we want to handle the hot reload in our processes\n        // (simply add an actionRoute for \"hotReloaded\")\n        store.dispatch({\n          type: 'HOT_RELOADED'\n        })\n      })\n    })\n  })\n  module.hot.accept('../ui/shared/sagas', () =\u003e {\n    // Accept changes to all of our sagas!\n  })\n}\n```\n\n***\n\n# Building your Processes\n\nSo now lets look at what a Process actually looks like, and what it can do for us. As\nshown above we start by building an ES6 class which extends ```Process```:\n\n```javascript\nimport Process from 'redux-saga-process'\nclass MyProcess extends Process { /* ... */ }\n```\n\n***\n\n## Process Properties\n\nOur classes can be configured using [static properties](http://exploringjs.com/es6/ch_classes.html).  In our examples\nwe are using the babel [transform-class-properties](https://babeljs.io/docs/plugins/transform-class-properties/) plugin.\n\n\u003e ***Note:*** All of the properties are completely optional.\n\n***\n\n\n### static ```config```\n\n\n```javascript\nclass MyProcess extends Process {\n  static config = {\n    /* Process Configuration Example */\n    // enabled?  Setting to false will stop the process from being built and/or added\n    // to the application. (default: true)\n    enabled: true\n    // providing this will indicate that we wish to reduce part of the redux store\n    reduces: 'myState',\n      // or\n      // reduces: ['myState', 'myState2']\n    // Should we run on the server side as well? (default: true)\n    ssr: true\n  }; // don't forget to add the semi-colon!\n}\n```\n\nProviding a config property allows you to modify how the process will be built and handled.\nWe plan to utilize this property to add flexibility and features in the future.  Below are\nthe properties that can be provided within this property.\n\n\n| Property        | Type(s)           | Description  |\n| -------------   |:-------------:| ----- |\n| **pid**          | _String_  | If using the `statics` connector, you will need to define a `pid` to use while importing a proceses exported values. |\n| **enabled**     | _Boolean_ | true/false if this process is enabled.  If set to \"false\" the process will be ignored on startup. |\n| **reduces**         | _String_ || _Array_ | a string indicating the name of the [reducer](http://redux.js.org/docs/basics/Reducers.html) this process should reduce. Or an array to provide multiple reducer keys.  \u003cbr /\u003e \u003cblockquote\u003e ***Note:*** If this property is not defined a reducer will not be generated. \u003c/blockquote\u003e |\n| **ssr**         | _Boolean_ | true/false if this process should run on the server as well as the client (default: true) |\n\n\u003e ##### Overlapping Reducer Names / Reducer Merge\n\u003e\n\u003e There are times that we needed multiple processes to reduce against the same key within our\n\u003e state.  If you define multiple processes that reduce the same state we will merge them into\n\u003e a single reducer and also attempt to merge and ```initialState``` that is provided.\n\u003e\n\u003e This is done internally by building a reducer which reduces an array of reducers while passing\n\u003e and merging initialState and any reduction filters we have specified.\n\u003e\n\u003e It is probably inadvisable to do this as it can cause conflicts.  It is generally a better\n\u003e idea to have each process reduce its own key within your state.\n\n\u003e ##### Defining Multiple Reducers for a Single Process\n\u003e\n\u003e Another option is to have a single process reduce multiple keys.  This is another feature which should\n\u003e be used lightly, however, it can be very useful in certain situations that you need to be able to place\n\u003e data in various places.\n\u003e\n\u003e When an array is provided, the reducer is expected to be an Object Literal where the keys are the key to reducer\n\u003e and the values are any accept reducer type.\n\n***\n\n\n### static ```initialState```\n\n\n```javascript\nclass MyProcess extends Process {\n  static config = {\n      // enabled reducing a portion of the redux store\n    reduces: 'myState'\n  };\n\n  static initialState = {\n    /* Initial 'myState' Reducer State */\n    myKey: 'myValue'\n  };\n}\n```\n\nWhen we are adding a reducer we may want to define an initialState that the\nstore should use.  This is done by providing the initialState property as\nshown above.  When your reducer is built we will pass the initialState as the\nstate on your first reduction.\n\n\u003e ***Tip:*** We also return the compiled initialState of all your processes as a result of\n\u003e the ```buildProcesses``` call.\n\n***\n\n\n### static ```reducer```\n\n\n```javascript\nimport { MY_TYPE, MY_OTHER_TYPE } from '../constants'\n\nclass MyProcess extends Process {\n  static config = {\n    reduces: 'myState'\n  };\n\n  static initialState = {\n    /* Initial 'myState' Reducer State */\n    myKey: 'myValue',\n    anotherKey: 'anotherValue'\n  };\n\n  // filters for MY_TYPE and MY_OTHER_TYPE\n  static reducer = {\n    [MY_TYPE]: (state, action) =\u003e ({\n      ...state,\n      myKey: action.value\n    }),\n    [MY_OTHER_TYPE]: (state, action) =\u003e ({\n      ...state,\n      anotherKey: action.value\n    })\n  };\n}\n```\n\nWe use \"higher-order-reducers\" to build special reducers that are used to filter the appropriate\nactions into your processes reducers (and trigger your sagas if specified).  Your reducer property\ncan be either a ```Reducer Function``` which itself is a reducer, an ```Object Literal``` (as shown above)\nwhich maps specific types into a reducer function, or an ```Array``` where each element itself is a reducer.\n\nObject reducers may also use wildcard matching, and a special shortcut is given that may be used.\n\n```javascript\n// shows shorthand method of specifying the type to filter for.  this is\n// is identical to the above example.\n\nclass MyProcess extends Process {\n  static config = {\n    reduces: 'myState'\n  };\n\n  static initialState = {\n    /* Initial 'myState' Reducer State */\n    myKey: 'myValue',\n    anotherKey: 'anotherValue'\n  };\n\n  // filters for MY_TYPE and MY_OTHER_TYPE\n  static reducer = {\n    myType: (state, action) =\u003e ({\n      ...state,\n      myKey: action.value\n    }),\n    myOtherType: (state, action) =\u003e ({\n      ...state,\n      anotherKey: action.value\n    })\n  };\n}\n```\n\n\n\u003e ***Note:*** Our higher-order-reducers will automatically return an unmodified state if no types match your specified\n\u003e handlers.\n\n\u003e ***Note:*** Reducers should be pure.  You can not access ```this``` within them. Instead\n\u003e you should pass any desired properties within a dispatched action.\n\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cb\u003eAn Example of using a Reducer Function\u003c/b\u003e\u003c/summary\u003e\u003cp\u003e\n\nHere is an example of a reducer format that matches the style shown in the \u003cb\u003eredux\u003c/b\u003e documentation:\n\n\n```javascript\nstatic reducer = function(state, action) {\n  switch(action.type) {\n    case MY_TYPE:\n      return {\n        ...state,\n        myKey: action.value\n      }\n    default:\n      return state\n  }\n};\n```\n\n\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cb\u003eAn Example of a Higher-Order-Reducer Generator (Click to Expand)\u003c/b\u003e\u003c/summary\u003e\u003cp\u003e\n\u003cbr /\u003e\nThis is not strictly important to see or understand, but for those of you that are interested\nin how we are building the reducers below is an example of the object filter reducer we showed\nin the first example.\n\n\n```javascript\nconst objectMapReducerGenerator =\n  (initialState, handlers = {}) =\u003e\n    (state = initialState, action) =\u003e\n      (\n        ! action || ! action.type || ! handlers[action.type] \u0026\u0026 state ||\n        handlers[action.type](state, action)\n      )\n```\n\u003c/p\u003e\u003c/details\u003e\n\n\n***\n\n\n### static ```actionRoutes```\n\n```javascript\nimport { put } from 'redux-saga/effects'\nimport { MY_TYPE, RECEIVED_ACTION } from '../constants'\n\nclass MyProcess extends Process {\n\n  static actionRoutes = {\n    [MY_TYPE]: 'myMethod'\n  };\n\n  * myMethod(action) {\n    yield put({ type: RECEIVED_ACTION })\n  }\n\n}\n```\n\nAction Routes allow us to define types that we are interested in handling as a\nside-effect and maps it to a method within your process.  If your method is a\ngenerator you can use any of the redux-saga API via yield within the method.\n\nactionRoutes support wildcard matching and the shorthand type defintion found\nin other properties.  Below we match using the shorthand property and route\nany types that start with \"ACTION_\" to our actionHandler.\n\n```javascript\nimport { put } from 'redux-saga/effects'\nimport { RECEIVED_ACTION } from '../constants'\n\nclass MyProcess extends Process {\n\n  static actionRoutes = {\n    myType: 'myMethod',\n    'ACTION_*': 'actionHandler'\n  };\n\n  * myMethod(action) {\n    yield put({ type: RECEIVED_ACTION })\n  }\n\n  * actionHandler(action) {\n    /* Handle types starting with ACTION_ */\n  }\n}\n```\n\n***\n\n### static ```actionCreators```\n\n```javascript\nclass MyProcess extends Process {\n\n  static actionCreators = {\n    trigger: [ 'action' ],\n    myType:  [ 'username', 'password' ],\n    fooType: { staticKey: 'staticValue' },\n    fnType:  (value, props, obj) =\u003e ({ value, props, ...obj })\n  };\n\n  * processStarts() {\n\n    yield* this.dispatch('trigger', 'this')\n      // dispatches action to reducers -\u003e\n      //  { type: 'TRIGGER', action: 'this' }\n\n    yield* this.dispatch('myType', 'myUsername', 'myPassword', { mergedKey: 'value' } )\n      // dispatches action to reducers -\u003e\n      //  { type: 'MY_TYPE', username: 'myUsername', password: 'myPassword', mergedKey: 'value' }\\\n\n    yield* this.dispatch('fooType', { mergedKey: 'value' })\n      // dispatches action to reducers -\u003e\n      //  { type: 'FOO_TYPE', staticKey: 'staticValue', mergedKey: 'value' }\n\n    yield* this.dispatch('fnType', 'foo', 'bar', { mergedKey: 'value' })\n      // dispatches action to reducers -\u003e\n      //  { type: 'FN_TYPE', value: 'foo', props: 'bar', mergedKey: 'value' }\n\n  }\n}\n```\n\n***\n\n### static ```selectors```\n\n```javascript\nclass MyProcess extends Process {\n  static config = {\n    reduces: 'myState'\n  };\n\n  static initialState = {\n    /* Initial 'myState' Reducer State */\n    foo: { nested: 'bar' },\n    baz: 'qux'\n  };\n\n  static selectors = {\n    local:   [ myState =\u003e myState.foo ],\n    global:  [ state =\u003e state, state =\u003e state.anotherKey.foo ],\n    global2: [ state =\u003e state.myState, myState =\u003e myState.baz ] // identical to above\n    composed: [\n      state =\u003e state.myState.foo.nested,\n      state =\u003e state.myState.baz,\n      (foo, baz) =\u003e ({ foo, baz })\n    ],\n  };\n\n  * processStarts() {\n    const local  = yield* this.select('local') // myValue\n    const global = yield* this.select('global')     // value of foo in anotherState key\n    const global2 = yield* this.select('global2')\n    const composed = yield* this.select('composed')\n    console.log(local, global, global2, composed)\n\n  }\n}\n```\n\nCurrently powered by the [reselect](https://github.com/reactjs/reselect) library (although at some point\nwe would like to allow for plugins instead), selectors allow us to capture the state of our Application\nwithin our processes.  While it is generally a best practice to handle state within the process for\nmost things related to our processes encapsulated logic (example: ```this.state```),\nit can be helpful to capture our state.\n\nYou can use the ```this.select``` function to conduct operations using the pre-built selectors.  However,\nyou can also dynamically specify selectors that were not built using the reselect package (using the selectors property).\n\nUnder-the-hood this.select is simply calling redux-sagas [yield select(selector)](https://redux-saga.github.io/redux-saga/docs/api/index.html#selectselector-args)\nand feeding it a [reselect selector](https://github.com/reactjs/reselect#createselectorinputselectors--inputselectors-resultfunc)\n\n***\n\n### static ```cancelTypes```\n```javascript\nimport { put } from 'redux-saga/effects'\nimport { CANCEL_PROCESS, USER_LOGOUT } from '../constants'\n\nclass MyProcess extends Process {\n\n  static cancelTypes = [\n    { type: CANCEL_PROCESS },\n    USER_LOGOUT\n  ];\n\n  * shouldProcessCancel(action) {\n    switch(action.type) {\n      case USER_LOGOUT: return true\n      case CANCEL_PROCESS:\n        if (action.name === this.name) return true\n      default: return false\n    }\n  }\n\n  * processCancels(action) {\n    /* Conduct Cleanup */\n  }\n\n  * processStarts() {\n    /* Cancel Ourself on Process Startup (As Example) */\n    yield put({ type: CANCEL_PROCESS, name: this.name })\n  }\n\n}\n```\n\n# Connecting to React Components\n\nWhen we want to connect actions and selectors provided by our processes, we have\nthe ability to use the \"statics\" module.  This will essentially connect to the\nconnect HOC that is provided - passing it the given processes public actions and/or\nselectors.\n\nYou setup what actions and selectors should be public when defining your selectors\nor actions by prefixing them with \"!\" (otherwise all will be imported).\n\n```javascript\nimport React, { Component } from 'react'\nimport { connect } from 'react-connect'\nimport statics from 'redux-saga-process/statics'\n\nclass DashboardGrid extends Component {\n  render() {\n    // ...\n  }\n}\n\nexport default statics(\n  {\n    grid: ['actions', 'selectors'],\n    processTwo: ['actions']\n  },\n  ({ selectors, actions }) =\u003e (\n    connect(\n      state =\u003e ({\n        grid: selectors.grid(state)\n      }),\n      actions\n    )(DashboardGrid)\n  ),\n  { prefixed: false }\n)\n```\n\n# Process API\n\nIn addition to the static properties, process contains special API helpers\nthat can be used within your process to make some patterns easier to work with\nand maintain.\n\n\u003e More Information Coming Soon...\n\n***\n\n## Process Task System\n\nTasks are essential to building powerful \u0026 asynchronous workflows within your\nprojects.  With the ```Process Task API``` it is simple to manage and maintain\nyour tasks.\n\nHere are a few key points about the Task API:\n\n- Tasks are given a `category` and `id` when created\n- If a task with the same `category` and `id` is created, the previous is automatically cancelled.\n- You can cancel a task by its `category` and `id`\n- You can cancel all tasks in a `category`\n- You can cancel all tasks\n- You can register callbacks to occur when a task is complete\n\n\u003e ***Note:*** This API is really a convenience wrapper around the ```redux-saga```\n\u003e [task](https://redux-saga.github.io/redux-saga/docs/api/index.html#task) system\n\u003e implemented using their [fork](https://redux-saga.github.io/redux-saga/docs/api/index.html#forkfn-args)\n\u003e feature.\n\n***\n\n### this.task.create(category, id)\n\n```javascript\nconst prop1 = 'foo', prop2 = 'bar'\nyield* this.task.create('category', 'taskID', this.myTask, prop1, prop2)\n```\n\n***\n\n### this.task.save(Task, category, id)\n\n```javascript\nconst task = yield fork([this, this.myTask], prop1, prop2)\nyield* this.task.save(task, 'category', 'taskID')\n```\n\n***\n\n### this.task.task(category, id)\n\n```javascript\nconst task     = yield* this.task.task('category', 'taskID')\nconst category = yield* this.task.task('category')\nconst all      = yield* this.task.task()\n```\n\n***\n\n### this.task.cancel(category, id)\n\n```javascript\nyield* this.task.cancel('category', 'taskID')\n// or\nyield* this.task.cancel('category')\n```\n\n***\n\n### this.task.onComplete(category, id, callback, ...props)\n\n```javascript\n* registerCallback() {\n  const foo = 'foo', bar = 'bar'\n  yield* this.task.onComplete('category', 'taskID', 'onComplete', foo, bar)\n}\n\n* onComplete(foo, bar) {\n  // foo === 'foo', bar === 'bar'\n}\n```\n\n***\n\n### this.task.cancelAll()\n\n```javascript\nyield* this.task.cancelAll()\n```\n\n## Process Observables\n\nUsed to handle \"push\" events rather than \"pull\" events.  For example, we use\nthis API heavily for handling [Firebase](https://www.firebase.com) real-time\nevents within our processes.\n\nObservables include a buffer, a cancellable promise, and more.  We will add\nmore information about how these works as we can, but feel free to try them\nout!\n\n\u003e More Information Coming Soon...\n\n```javascript\n* observer(ref, type, id) {\n  const { getNext, onData } = this.observable.create(id)\n  const observerID = ref.on(type, onData)\n  try {\n    while (true) {\n      const data = yield call(getNext)\n      yield fork([this, this.processReceived], data)\n    }\n  } catch(error) {\n    console.warn('Catch Called in Observer', error.message)\n  } finally {\n    if (yield cancelled()) {\n      console.log('Observable Cancelled')\n      ref.off(type, observerID)\n    }\n  }\n}\n```\n\n***\n\n### this.observable.create()\n\n# Reducer Generators\n\nInternally we use ```reducer generators``` to build reducers which reduce reducers.\nThis allows us to filter actions into our methods efficiently and allows us to build much\nof the syntax we use for the static properties such as ```actionRoutes```.  You can\nimport these and use them elsewhere if desired.\n\n```javascript\nimport { reducerReducer, arrayMapReducer, objectMapReducer } from 'redux-saga-process/generators'\n```\n\n***\n\n### objectMapReducer(initialState, handlers, context)\n\nReduces an object with types as their keys and reducers as their values.\n\n```javascript\nconst reducer = objectMapReducer(\n  { foo: 'bar' },\n  {\n    'MY_TYPE': (state, action) =\u003e ({\n      ...state,\n      key: action.value\n    }),\n    'ANOTHER_TYPE': (state, action) =\u003e ({\n      ...state,\n      another: action.value\n    })\n  }\n)\n```\n\n***\n\n### arrayMapReducer(initialState, reducerArray, context)\n\nReduces an array of reducers.\n\n```javascript\nconst reducer = arrayMapReducer(\n  { foo: 'bar' }, // initialState\n  [\n    (state, action, context) =\u003e {\n      /* reducer here */\n      return state\n    },\n    (state, action, context) =\u003e {\n      /* reducer here */\n      return state\n    }\n  ],\n  { shared: 'data' }\n)\n```\n\n***\n\n### reducerReducer(initialState, reducer, context)\n\nA reducer which reduces a reducer.  The main purpose of this generator is to allow us\nto inject information into the reducer before executing.  This is mostly used internally\nbut you may find a use for it.\n\n```javascript\nreducerReducer(\n  { foo: 'bar' }, // initialState\n  (state, action, context) =\u003e {\n    switch(action.type) {\n      case 'MY_TYPE':\n        return {\n          ...state,\n          key: action.value\n        }\n      default:\n        return state\n    }\n  },\n  { shared: 'data' } // context\n)\n```\n\n***\n\n### Special Thanks \u0026 Inspirations\n\n- **Dan Abramov [@gaearon](https://github.com/gaearon)** - Because it's the cool thing to do to thank him and obviously because of his endless contributions to the community including [redux](https://github.com/reactjs/redux) which is what this package is based upon (obviously).\n- **Yassine Elouafi [@yelouafi](https://github.com/yelouafi) / [@redux-saga](https://github.com/redux-saga)** - For bringing us [redux-sagas](https://github.com/redux-saga/redux-saga) and for indirectly inspiring the process concept while assisting us with questions.\n- **Steve Kellock [@skellock](https://github.com/skellock)** - [reduxsauce](https://github.com/skellock/reduxsauce) - Originally we used reduxsauce to handle some of the handling of data.  Many parts of this package are heavily inspired by the great package they have provided!","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdash-os%2Fredux-saga-process","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdash-os%2Fredux-saga-process","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdash-os%2Fredux-saga-process/lists"}