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-promise-await-middleware

v1.0.2

Published

Redux middleware and reducer to handle async actions with promises.

Downloads

6

Readme

Redux Promise Await Middleware

Combination of Redux middlewares and reducers that help in dealing with async actions and server side rendering.

It exports three main modules:

  • promiseAwaitMiddleware
  • promiseAwaitReducer
  • promiseMiddleware

Installation

npm i redux-promise-await-middleware --save

Promise Await Middleware + Reducer

The middleware and the reducer work in tandem to make server side rendering with React easy when you have to prefetch data.

This is done by keeping reference to any dispatched promises and only rendering the application and sending the response to the client after they have resolved. See the example below.

Usage:

store.js:

import { createStore, compose, applyMiddleware } from 'redux'
import { promiseAwaitMiddleware, promiseAwaitReducer } from 'redux-promise-await-middleware'

export default (initialState = {}) => {
  const store = createStore(
    {
      __promises: promiseAwaitReducer()
    },
    initialState,
    compose(
      applyMiddleware(
        promiseAwaitMiddleware()
      )
    )
  )

  return store
}

Examples:

This is just one example on how to handle server side rendering while waiting for all async actions to finish. Doing it this way you can dispatch actions normally inside componentWillMount() method so that SSR is completely transparent for your app.

One controversial issue here is that this effectively re-renders the React app multiple times (at least 2) until sending the final response. In my tests on a bigger application it takes about 50-70ms per render.

server.js:

import express from 'express'
import React from 'react'
import { renderToString } from 'react-dom/server'
import { Provider } from 'react-redux'

import App from 'components/App'
import createStore from 'store' // the file above

// normal express handling
const app = express()
app.use((req, res) => {
  // create separate store for each request
  const store = createStore()
  
  // see below
  render(req.url, store)
    .then((html) => {
      res.render('index', {
        html,
        initialState: store.getState()
      })
    })
})

// render the application but wait for any async actions to resolve
function render (url, store) {
  const promises = store.getState().__promises || []
  const promisesCount = promises.length

  return Promise.all(promises)
    .then(() => {
      const html = renderToString((
        <Provider store={store}>
          <App />
        </Provider>
      ))

      // if amount of promises in the store has grown
      // then wait for those new promises to resolve and re-render again
      const newPromises = store.getState()._promises || []
      if (newPromises.length > promisesCount) {
        return render(url, store)
      }

      return html
    })
}

Promise Middleware

This is very similar to redux-promise-middleware package. It kicks in when a dispatched action has a property promise that is indeed a Promise and splits the action into three separate actions:

  • [action_name]//PENDING dispatched immediatelly instead of the original action, contains the original promise
  • [action_name] dispatched when the promise is resolved, contains result property which is what the promise resolved with and doesn't contain the original promise
  • [action_name]//REJECTED dispatched when the promise is rejected, contains error property and doesn't contain the original promise.

(The names are configurable).

Usage:

store.js:

import { createStore, compose, applyMiddleware } from 'redux'
import { promiseMiddleware } from 'redux-promise-await-middleware'

export default (initialState = {}) => {
  const store = createStore(
    {}, // your reducers
    initialState,
    compose(
      applyMiddleware(
        // install our middleware, the options argument is optional and what you see here are defaults
        promiseMiddleware({
          pendingSuffix: '//PENDING',
          resolvedSuffix: '//',
          rejectedSuffix: '//REJECTED'
        })
      )
    )
  )

  return store
}

Examples:

const GET_DATA = 'GET_DATA'

// typical reducer that updates the state with promise status so that UI can give nice feedback on what is happening
function dataReducer (state = {}, action) {
  switch (action.type) {
    // received immediatelly when original action is dispatched, we can show a loading indicator to the user
    case GET_DATA + '//PENDING':
      return {
        ...state,
        data: {},
        loading: true,
        error: false
      }
    }

    // received when the promise in the original action successfully resolves, we can show the data to the user
    case GET_DATA:
      return {
        ...state,
        data: action.result,
        loading: false,
        error: false
      }

    // received when the promise in the original action is rejected, we can show the error to the user
    case GET_DATA + '//REJECTED':
      return {
        ...state,
        data: {},
        loading: false,
        error: action.error
      }

    default:
      return state
  }
}

// just dispatch regular action
dispatch({
  type: GET_DATA,
  promise: fetch('/data/')
})

If you ignore the //PENDING and //REJECTED actions and just deal with the original action name, this middleware can be totally transparent for you while you can be sure that any data you fetch is there.

License

MIT, see LICENSE.md.

Copyright (c) 2017 Michał Pałys-Dudek