npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

redux-serial-effects

v0.0.26

Published

Predictable side-effect middleware for the predictable state container

Downloads

64

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
  2. 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

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.