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

v0.0.1-alpha.5

Published

Enhances your redux store with optimism.

Readme

Build Status Coverage Status Dependencies

redux-optimism

Enhances your redux store with optimism.

Take care, this package is in alpha stage!

Installation

Just

npm install redux-optimism

// or
yarn add redux-optimism 

Usage

The module was designed with redux-thunk in mind (like in the example). It'll probably work well with other async patterns though.

1. Enhance your reducer

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import {makeOptimistic} from 'redux-optimism'

import rootReducer from './reducers/index';

const store = createStore(
    makeOptimistic(rootReducer),
    applyMiddleware(thunk)
);

2. Dispatch with optimism

import {getOptimism} from 'redux-optimism'

// Our thunk
function thunkAction() {
    return async dispatch => {
        let {optimistic, commit, rollback} = getOptimism(dispatch)
        optimistic({type: 'UPDATE_DATA'})
        optimistic({type: 'UPDATE_OTHER_DATA'})
        try {
            await apiCall()
            commit()    
            dispatch({type: 'OTHER_ACTION'})
        } catch (e) {
            rollback()   
        }
    }
}

Remarks

Benefits

  • You can dispatch as many optimistic actions as you like.
  • Actions after an optimistic action won't get lost.
  • The state is also calculated correctly when you have different optimistic sessions ("optimisms"), that get rolled back or committed in random order. Just keep in mind, that no non-optimistic action may happen that depends on an optimistic action. For example there mustn't be a delete key for an optimistically created item.
  • Fully compatible to Flux Standard Actions.
  • Thoroughly typed — get the full power of your IDE.
  • Zero dependencies.

Pitfalls

  • This package is alpha! It's functionality is well tested, but I don't know, how well or badly it integrates with other redux stuff. Please open an issue if you find a failing example!
  • Optimistic updates reduce the amount of comprehensibility in your store.
  • redux-optimism increases the size of your store. With short optimistic durations and only little optimistic actions it's about double the size of your realistic store. In other cases it's going to be more (depends on the size of your actions).
  • You have to take care, that the user can't take actions that depend on an optimistic update.

Usage with combineReducers

CombineReducers doesn't like keys other than it's own. If you just wrap combineReducers, redux-optimism won't work. Thus we have to add the key:

import {combineReducers} from 'redux'
import {user, userInterface} from "store/user/reducers"

function optimism(state: any = {}, action: any) {
    return state
}

const rootReducer = combineReducers({
    user,
    userInterface,
    optimism
})

export {rootReducer}

Check for optimistic actions in your own reducers

Optimistic actions are marked with action.meta.optimisticId = ID. But you can also just

import {isOptimistic} from 'redux-optimism'

function reducer(state: any, action: any) {
    if (isOptimistic(action)) {
        ...
    }
}

What does getOptimism do?

getOptimism is a really simple function: It generates a new optimisticId, dispatches

{
    type: 'INIT_OPTIMISM',
    payload: {optimisticId: optimisticId}
}

and returns the three functions optimistic(action), commit() and rollback(). Commit and rollback are just

dispatch({
    type: 'COMMIT_OPTIMISM',
    payload: {optimisticId: optimisticId}
})

and

dispatch({
    type: 'ROLLBACK_OPTIMISM',
    payload: {optimisticId: optimisticId}
})

while optimistic(action) dispatches the given action with action.meta.optimisticId set:

dispatch({
    ...action,
    meta: {optimisticId: optimisticId}
})

So, you could use the complete functionality of redux-optimism without getOptimism. However, I recommend using getOptimism, as it's a bit more opinionated:

If an optimism was initialized and neither committed or rolled back after 20 seconds, it will log an error and will automatically get rolled back. Why is this important? If you don't commit or rollback an optimism for a longer time, your state can be hard to understand later. You should try to make the state as deterministic as possible. Also the store grows in size if an optimistic action is pending for a longer time.

import { createStore, applyMiddleware } from 'redux';
import {makeOptimistic, getOptimism} from 'redux-optimism'


function rootReducer(previousState: any = {}, action: any) {
    if (action.type === 'INCREMENT') {
        return {
            ...previousState,
            test: 1
        }
    } else {
        return previousState
    }
}

const store = createStore(
    makeOptimistic(rootReducer)
)

let {optimistic, commit, rollback} = getOptimism(store.dispatch)
optimistic({type: 'INCREMENT'})

console.log(store.getState().test)
// Logs 1

// Wait for 20s

console.log(store.getState().test)
// Logs undefined

You can change the behavior easily: getOptimism takes more arguments:

let {optimistic, commit, rollback} = getOptimism(
    store.dispatch, 
    60000, // Set the timeout to 60s
    (optimisticId, commit, rollback) => {commit()}) // Commit in case of a timeout

Or, if you want to use another default behaviour

import {setDefaultTimeout, setDefaultTimeoutHandler} from 'redux-optimism'

setDefaultTimeout(10000) // Use 10s as the default timeout
setDefaultTimeoutHandler((optimisticId, commit, rollback) => {
    console.log("I don't care")
})

Why did I write this package?

There are other optimistic state enhancers:

I wanted an intersection of both of them with a bit on top:

  • It should only use one copy of the state (redux-optimistic-ui)
  • FSA compliance (redux-optimistic-ui)
  • No need to change the structure of the application state (redux-optimist — redux-optimistic-ui requires you to wrap getState() every single time with ensureState()).
  • Don't care about IDs (none of them)
  • Provide types (none of them)

Additionally, redux-optimist has some issues and pull requests that are open several years. So I wrote this package. But keep in mind: This is in alpha stage!

License

MIT