RSync: Redux async middleware
RSync is an alternative to redux-saga to handle async actions without generator. It makes handling complicated async flow easier and offers a great readability.
Table of Contents
Demo
For a demo, click here.
Installation
yarn add redux-rsync
Getting Started
1. Apply rsync middlware
redux/index.js
const store =
2. Decorate actions with async or flow metadata
redux/action.js
... { return type: 'REQUEST_GET_USER' payload meta: async: apiuser resolve: type: 'RESOLVE_REQUEST_GET_USER' reject: type: 'REJECT_REQUEST_GET_USER' take: 'latest' }...
redux/flow.js
... { return type: 'LOAD_INITIAL_DATA' payload meta: flow: actions: effect: requestGetUser !responsedataargsuser prepare: loadInitialDataParamsrequestGetPosts effect: requestGetPosts resolve: type: 'RESOLVE_LOAD_INITIAL_DATA' reject: type: 'REJECT_LOAD_INITIAL_DATA' take: 'every:serial' }...
Documentation
RSync works by decorating actions with async
and/or flow
metadata
Async
Example
... { return type: 'REQUEST_GET_USER' payload meta: async: apiuser resolve: type: 'RESOLVE_REQUEST_GET_USER' reject: type: 'REJECT_REQUEST_GET_USER' take: 'latest' }...
Properties
Property | Type | Value | Description |
---|---|---|---|
effect |
function | payload => {} |
Async side effect to run |
resolve |
object | { type: '<ACTION_NAME>' } |
Will be dispatched if the effect execution is successful. Payload and effect result/response will be passed to the reducer automatically |
reject |
object | { type: '<ACTION_NAME>' } |
Will be dispatched if the effect execution is failed. Payload and error will be passed to the reducer automatically |
take |
string | every:parallel (default), latest |
latest : if an action effect still running when another action with the same type is dispatched, then the previous action will be cancelledevery:parallel : take all dispatched actions |
Flow
Example
// async.js ... { return type: 'REQUEST_GET_USER' payload meta: async: apiuser resolve: type: 'RESOLVE_REQUEST_GET_USER' reject: type: 'REJECT_REQUEST_GET_USER' take: 'latest' } { return type: 'REQUEST_GET_POSTS' payload meta: async: apipostindex resolve: type: 'RESOLVE_REQUEST_GET_POSTS' reject: type: 'REJECT_REQUEST_GET_POSTS' take: 'latest' }... // flow.js ... { return type: 'LOAD_INITIAL_DATA' payload meta: flow: actions: // will be executed in order effect: requestGetUser !responsedataargsuser prepare: loadInitialDataParamsrequestGetPosts effect: requestGetPosts // to execute multiple async actions in parallel, wrap them inside another array prepare: loadInitialDataParamsdoFoo effect: doFoo prepare: loadInitialDataParamsdoBar effect: doBar resolve: type: 'RESOLVE_LOAD_INITIAL_DATA' reject: type: 'REJECT_LOAD_INITIAL_DATA' take: 'every:serial' }...
Properties
Property | Type | Value | Description |
---|---|---|---|
actions |
array[object/array] or | [{ effect: () => {}, ... }, ...}] |
Array of actions to run. The action will support these following properties: effect , prepare , break The actions will be executed in order. To run the actions in parallel, Wrapping the actions inside another another array will do it. (see example above) effect : function that will return redux action with meta:async property. (see example above)prepare : function to prepare result/response from previous async action into params for the current actionbreak : function to evaluate the result/response from the action. return true to break the flow or return false to continue |
resolve |
object | { type: '<ACTION_NAME>' } |
Will be dispatched if the effect execution is successful. Effect result/response will be passed to the reducer automatically. |
reject |
object | { type: '<ACTION_NAME>' } |
Will be dispatched if the effect execution is failed. Error will be passed to the reducer automatically. |
take |
string | first (default), every:serial , every:parallel |
first : will not accept any flow actions with the same type with the one that currently running unti it's doneevery:serial : take all dispatched flow actions with the same type , put them in a queue and execute them in serial |
Contributing
We appreciate feedback and contribution to this repo! Before you get started, please see the following: