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 🙏

© 2026 – Pkg Stats / Ryan Hefner

redux-waitfor

v1.0.0

Published

Reducer combinator that allows reducers to wait upon each other.

Readme

redux-waitfor

Reducer combinator that allows reducers to wait upon each other.

Warning

You might not need to use this. See this discussion: waitFor leads to wrong design.

In the motivation section, I’ve explained the alternative without using waitFor, but since I’ve alread spent time creating and testing this thing, I’ll put it online anyway.

Motivation

When building a Redux app, there are some cases that a reducer does not only depend on the state and action, but also depend on the state returned by another reducer.

For instance, I am building an expense tracking application using speech recognition. Therefore, there are these events:

  • SpeechRecognitionInitialize (fired when tapping the mic)
  • SpeechRecognitionStart (fired when the app is ready to listen)
  • SpeechRecognitionResult (fired as you speak)
  • SpeechRecognitionEnd (fired when speech recognition ended)

My transcript reducer consumes these series of events (actions) and produces the transcript of what I just said (e.g. “40 Baht food”).

From the transcript, I need to derive an interpretation of the spoken text (e.g. { amount: 40, category: "food" }).

From the interpretation, I need to derive an expense entry which will be saved into the database. However, before I save it to the database, I want to be able to edit it before I save.

There are two choices in architecturing this:

  1. Put transcript, interpretation, and stagedDatabaseEntry into the store. This is the first idea that comes into my mind. “Surely I should do it this way,” I said to myself.

    But this means we need to set up dependencies between these reducers, so that when speech is recognized, the interpretation reducer has access to the latest transcript, and stagedDatabaseEntry has access to the latest interpretation.

    This is where redux-waitfor comes into play.

    Think of this approach as using materialized views. Also consider the next option, as this option might not be the most appropriate one.

  2. Only put transcript in the store, and use reselect to derive both interpretation and stagedDatabaseEntry.

    For the last requirement that I want to modify the stagedDatabaseEntry before actually saving it to the database, I’ll just store the stagedDatabaseOverrides instead and derive them on-the-fly.

    This solution is less obvious to me, and I can only think of it as I write the documentation of this redux-waitfor.

    Think of this approach as using a (non-materialized) view of the database. In fact, this may be a better option!

Usage

If you insist on using this thing, first, you need to import it:

import { waitFor, combineReducers } from 'redux-waitfor'

waitFor(key, inject)

This is a function that takes a reducer, and returns a reducer that waits for data from another part of the store with the specified key.

const interpretationReducer = waitFor('transcript', transcript =>
  (state = { }, action) => deriveInterpretationFromTranscript(transcript)
)

But wait! How can a reducer wait for more data? That seems impossible. Let’s try invoking this magical reducer.

> interpretationReducer(void 0, action)
[Function]

A function (a thunk) is returned instead of the new state! This signifies that we need more data from other parts of the store. We then pass the state from other parts of the store into that thunk:

> interpretationReducer(void 0, action)({
    transcript: '40 Bath food'
  })
{ amount: 40, category: 'Food' }

Now we have the actual, new state.

What really happens is that when we invoke that thunk waitFor, it will inject the state of the thing we’re waiting for into the inject parameter. That inject function then takes the required data and returns a reducer, which is then immediately invoked.

combineReducers(reducers)

This is a version of Redux’s combineReducers that works with thunks.

How it works: Perhaps the easiest way to explain it is by examples. Here is our current state:

{ transcript: '',
  interpretation: null,
  stagedDatabaseEntry: null }

An action happened. It is dispatched to each reducer, just like Redux’s combineReducers. Some reducer returned the new state, and some returned a thunk:

{ transcript: '40 Baht food',
  interpretation: [Function],
  stagedDatabaseEntry: [Function] }

We then enter the digest cycle. We send this object into each thunk.

Since transcript is available, the thunk injected it to and invokes the reducer. Meanwhile, since interpretation is not available yet at that time, the thunk returned itself.

This is the resulting state:

{ transcript: '40 Baht food',
  interpretation: { amount: 40, category: 'food' },
  stagedDatabaseEntry: [Function] }

This means we need another digest cycle. We did the same, and obtain the final state:

{ transcript: '40 Baht food',
  interpretation: { amount: 40, category: 'food' },
  stagedDatabaseEntry: { /* ... */ } }

For more example and tests, see example.js (which also serves as a unit test — it’s pretty comprehensive!).

As you can see, this is quite advanced and requires lots of explanation. Perhaps you can take this advice from The Zen of Python instead:

If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea.

So, unless you really need to, don’t use this library!