Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/wix-incubator/redux-serial-effects
Predictable side-effect middleware for the predictable state container
https://github.com/wix-incubator/redux-serial-effects
effects middleware redux serial-effects side-effects
Last synced: about 1 month ago
JSON representation
Predictable side-effect middleware for the predictable state container
- Host: GitHub
- URL: https://github.com/wix-incubator/redux-serial-effects
- Owner: wix-incubator
- License: mit
- Created: 2017-08-27T11:30:57.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2023-02-22T08:59:08.000Z (almost 2 years ago)
- Last Synced: 2024-08-22T21:27:48.475Z (5 months ago)
- Topics: effects, middleware, redux, serial-effects, side-effects
- Language: JavaScript
- Homepage:
- Size: 105 KB
- Stars: 13
- Watchers: 41
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Redux Serial Effects
Predictable side-effect middleware for the predictable state container.
## Approach
Serial effects does two things:
1. Implements an Elm-like architecture for executing side-effects
1. Manages a queue of side-effects for execution (hence the name)The first promotes DRYness, reduces fragmentation of business logic, and increases composability.
The second makes side-effects predictable by executing side-effects in the order they were
generated.### Generating Side-effects
Side-effects are generated in similar fashion to the Elm Architecture. The most notable difference
being that the `reducer` is not responsible for generating side-effects. A new player is involved,
called `subscriber`, which differs from a Redux listener in several aspects:1. Subscribers receive both the state before the dispatched action was processed by the reducers
(a.k.a. `from`), and the final state after the reducer changed it (a.k.a. `to`).
2. Subscribers maybe return a list of effects to execute.Serial-effects tracks changes to the state, and each time a change is detected, calls all registered
subscribers. Each subscriber receives both the state before the dispatched action was processed by the reducers
(a.k.a. `from`), and the final state after the reducer changed it (a.k.a. `to`), and my return a list of effects to execute.
Serial-effects will collect all these effects and will execute them as described in the next section.### Executing Side-effects
Once all subscribers have been called for a given state transition, and have returned their lists of
effects to execute, Serial-effects will organise these effects in two groups: immediate, and
queued.Immediate effects are executed synchronously before `dispatch` returns. Any exception thrown by an
immediate effect is thrown to the code that called `dispatch`. Any promises returned by immediate
effects are ignored.Once all immediate effects have completed, queued effects are put into the middleware's internal
execution queue, to be executed when their turn arrives. Dispatch will then return. All queued
effects produced by a single transition are queued together and will be executed concurrently. The
queue will wait for all promises returned by these effects before advancing to the next group of
queued effects. It stops waiting if any promise is rejected, and execution rights are passed to the
next group of queued effects.### Completion Actions
Each effect may specify which action should be dispatched, if any, when it completes. For every
effect that completes, either successfully or not, the middleware will dispatch the action to the
store, with the effect's results.The action's payload will hold whether the effect completed successfully or not, and what value or
error it returned or resolved/rejected with.## Usage
```javascript
const { createStore, applyMiddleware } = require('redux')
const { createMiddleware } = require('redux-serial-effects')// actions
const SET_DISPLAY_ITEM = 'SET_DISPLAY_ITEM'
const DATA_RESPONSE_SUCCESS = 'DATA_RESPONSE_SUCCESS'
const DATA_RESPONSE_FAILURE = 'DATA_RESPONSE_FAILURE'const setItemToDisplay = id => ({
type: SET_DISPLAY_ITEM,
id
})const dataResponseSuccess = data => ({
type: DATA_RESPONSE_SUCCESS,
data
})const dataResponseFailure = error => ({
type: DATA_RESPONSE_FAILURE,
error
})// effects
const getDataFromRemoteServiceEffect = id => ({
run: () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve({ content: 'item data' }), 10)
}),
isQueued: true,
resultActionCreator: (error, payload) =>
error ? dataResponseFailure(error) : dataResponseSuccess(payload)
})// reducer
const initialState = {
itemToDisplay: {
id: 0,
data: {}
},
errorState: false,
errorDescription: null
}const getDisplayItemId = state => state.itemToDisplay.id
const reducer = (state, action) => {
switch (action.type) {
case SET_DISPLAY_ITEM:
return Object.assign({}, state, {
itemToDisplay: Object.assign({}, state.itemToDisplay, {
id: action.id
})
})case DATA_RESPONSE_FAILURE:
return Object.assign({}, state, {
errorState: true,
errorDescription: action.error
})case DATA_RESPONSE_SUCCESS:
return Object.assign({}, state, {
errorState: false,
errorDescription: null,
itemToDisplay: Object.assign({}, state.itemToDisplay, {
data: action.data
})
})default:
return state
}
}// subscriber
const subscriber = ({ from, to, hasChanged }) => {
if (hasChanged(getDisplayItemId)) {
return getDataFromRemoteServiceEffect(to.itemToDisplay.id)
}
}// store
const { middleware, subscribe } = createMiddleware()
subscribe(subscriber)
const store = createStore(reducer, initialState, applyMiddleware(middleware))store.dispatch(setItemToDisplay(1))
```## Status of the API
Public API is not stable yet.