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-ops

v1.2.0

Published

A Redux reducer/middleware for managing async and operational states.

Downloads

23

Readme

redux-ops npm Build Status Coverage Status

A Redux reducer/middleware for managing asynchronous and operational states.

Getting Started

You can either install the module via npm or yarn:

npm install redux-ops --save
yarn add redux-ops

Motivation

Maintaining asynchronous and operational states is an integral part of almost every modern (web) app, but an often discussed topic when it comes to their implementation and the Redux state structure to store them accordingly.

redux-ops is trying to take this concern away by providing a reducer, an optional middleware with action creator Blueprints, actions, selectors and utilities to

  • maintain aforementioned states in a more consistent way (e.g. requests, transaction-like processes),
  • communicate these async/operational state transitions,
  • prevent cluttering of state slices with individual sub-states
  • and to have a centralized place to store them.

Examples

Introduction: Operations

At its core, redux-ops consists of a reducer with a set of actions for the creation, update and deletion of Operations.

An Operation represents any async or operational task in the form of the following object that gets updated and persisted within the opsReducer.

{
  id: '74168d',
  status: 'success',
  data: [{ "id": 1, "name": "Jurassic World" }],
}

In the following example, we are going to fetch some movie data from a server and use these core actions to perform the state transitions.

import { createStore, combineReducers } from 'redux';
import opsReducer, { actions, selectors } from 'redux-ops';

// Create store and set up the reducer
const store = createStore(combineReducers({ ops: opsReducer }));
// Create an Operation in its default state
const opId = '74168d';
dispatch(actions.startOperation(opId));

// State => { ops: { id: '74168d', status: 'started' } }
// Fetch movies and update the previously created Operation
fetch('https://example.com/movies.json')
  .then(response => response.json())
  .then(movies => dispatch(actions.updateOperation(opId, OpStatus.Success, movies)))
  .catch(error => dispatch(actions.updateOperation(opId, OpStatus.Error, error.message)));

// State => { ops: { id: '74168d', status: 'success', data: {...} } }

A set of selectors and utility functions allows to, for example, retrieve the current state of an Operation, or clean it up when it's no longer needed.

// Get the Operation state by using one of the provided selectors
console.log(selectors.getOpById(store.getState(), opId));

// Op => { id: '74168d', status: 'success', data: {...} }
// Delete the Operation
dispatch(actions.deleteOperation(opId));

// State => { ops: {} }

Live Demo

Blueprints & Middleware

redux-ops also comes with an optional middleware that enables the usage of so-called action Blueprints to reduce boilerplate by either using already defined action creators like the ones in the example below or by solely relying on the built-in Operations.

import { createStore, combineReducers, applyMiddleware } from 'redux';
import opsReducer, { opsMiddleware } from 'redux-ops';

// Set up reducer and apply the middleware
const store = createStore(
  combineReducers({ ops: opsReducer },
  applyMiddleware(opsMiddleware)
);
// We can either create/use existing actions (recommended), or let the Blueprints handle it for us.
const fetchMovies = () => ({ type: movieFetcher.START });
const didFetchMovies = movies => ({ type: movieFetcher.SUCCESS, payload: { movies } });

The createBlueprint function wraps our action creators into actions that will be processed by the middleware.

Since we already have two designated action creators to initiate (fetchMovies) and complete (didFetchMovies) the Operation, we can leverage them, or let the auto-generated action creators handle non-defined cases such as the error one, which we decided to not define for now.

import { createBlueprint } from 'redux-ops';

// Create a new Blueprint for managing state
const movieFetcher = createBlueprint('FETCH_MOVIES', {
  start: fetchMovies,
  success: didFetchMovies,
});

When creating a new Blueprint, an id/action type needs to be passed in. This identifier can be a string or number and is, amongst other use cases, also utilized for other concepts such as Operation broadcasting and unique Operations.

To kick-off the Operation, we need to dispatch the movieFetcher.start() action.

dispatch(movieFetcher.start());

The middleware will process the Blueprint-Action, start a new Operation with the id FETCH_MOVIES (which can be chosen arbitrarily and is not directly related to existing types) and additionally dispatch the original fetchMovies() action.

The request itself can then be sent in whatever way you prefer.

// Fetch movies and update the previously started Operation
fetch('https://example.com/movies.json')
  .then(response => response.json())
  .then(movies => dispatch(movieFetcher.success(movies)))
  .catch(error => dispatch(movieFetcher.error(error.message));
// Get the Operation state by using one of the provided selectors
console.log(selectors.getOpById(store.getState(), movieFetcher.id));
// Delete the Operation if needed
dispatch(movieFetcher.delete());

Live Demo

Documentation

License

MIT