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

use-optimistic

v1.0.0

Published

This is a set of react hooks to help manage optimistic states.

Readme

use-optimistic

This is a set of react hooks to help manage optimistic states.

As previously stated in redux-optimistic-thunk, manually managing optimistic states, commits, rollbacks and transactions are not ideal model of state management. React hooks provides powers to manage states in a more functional way, and this library aimed to build optimistic functions above hooks.

This library required ES6 Generators to work.

Usage

Install

npm install use-optimistic

This library provides 3 hooks to developers.

useOptimisticFactory

This is the fundamental hooks which manages a full functional optimistic state:

const [state, dispatch] = useOptimisticFactory(factory, initialState);

The factory parameter referes to a function receiving a payload object and returns either:

  • A state reducer (state: T) => T, this reducer will be executed immediately providing current state, the returned state is going to be the next state.
  • A tuple of [asyncWorkflow, optimisticReducer] which defines an async workflow and a optimistic reducer to take place before async operations complete.

An asyncWorkflow is a generator function which yields a reducer or a Promise instance.

Any time a state reducer is yielded, it will be executed against current state and generates the next state.

When a Promise is yielded, it will be awaited, the resolved value will be returned to yield statement.

Right after the first Promise is yielded, the optimisticReducer will be executed to generate an optimistic state, inside useOptimisticFactory hook it will automatically rollback this optimistic state after Promise is settled (either fulfilled or rejected).

Note that optimisticReducer will be only executed on the first Promise, so if asyncWorkflow yields several Promises the later ones will not take benefit from optimistic state.

The return value of useOptimisticFactory is the same signature of useReducer, the state represents the latest state and dispatch is a function to feed payload to factory argument.

One thing to metion is that dispatch will be different if factory changes, this is different to the built-in useReducer hook, we recommend to cache factory with useCallback.

This is a simple example to manage a todo list with useOptimisticFactory:

const factory = useCallback(
    ({type, payload}) => {
        switch (type) {
            case 'DELETE':
                return items => {
                    const index = items.findIndex(i => i.id === payload);
                    return [
                        ...items.slice(0, index),
                        {...items[index], deleted: true},
                        ...items.slice(index + 1),
                    ];
                };
            case 'CREATE':
                return [
                    function* create() {
                        // Await an async api call
                        const newTodo = yield saveTodo(payload);
                        // Insert the returned new todo to list, with pending set to false
                        yield items => [
                            ...items,
                            {...newTodo, pending: false, deleted: false},
                        ];
                    },
                    items => [
                        ...items,
                        // Insert an optimistic item with property pending set to true,
                        // this item will be removed after saveTodo resolves
                        {id: uid(), text: payload, pending: true, deleted: false},
                    ],
                ];
            default:
                return s => s;
        }
    },
    []
);
const [todos, dispatch] = useOptimisticFactory(factory, []);

You can call dispatch at any time, parallelism is handled internally. See demo to find more details.

useOptimisticState

Like useState and useReducer, useOptimisticState is a simmple encapsulation to useOptimisticFactory.

const [state, setState] = useOptimisticState(initialState);

The setState can receive 2 different arguments:

setState(nextState);
setState(promise, optimisticNextState);

If only 1 argument is provided, this works exactly the same as useState hook, nextState can be either a state object or a state reducer (state: T) => T.

When 2 arguments are provided, the first one is a Promise which resolves to a nextState (which is a state object or a reducer), the second is a nextState takes optimistic effects.

const [todos, setTodos] = useOptimisticState([]);
const addTodo = todo => setState(
    (async () => {
        const newTodo = await saveTodo(todo);
        // We recommend to use a reducer since it is asynchronous
        return todos => [...todos, {...newTodo, pending: false, deleted: false}];
    })(),
    // Optimistic next state is executed synchronously, it can be a single state object
    [...todos, {...todo, pending: true, deleted: false}]
);

useOptimisticTask

This is a binding of useOptimisticState and an async task.

const [state, run] = useOptimisticTask(task, optimisticTask);
  • The task is an async function (arg: TArg) => Promise<TState>.
  • The optimisticTask is a sync version of task provides an optimistic response (arg: TArg) => TState.
  • Returned run function receives the same argument as task.
const newTodo = async todo => {
    const newTodo = await saveTodo(todo);
    // We recommend to use a reducer since it is asynchronous
    return todos => [...todos, {...newTodo, pending: false, deleted: false}];
};
const optimisticNewTodo = todo => todos => [...todos, {...todo, pending: true, deleted: false}];
const [todos, addTodo] = useOptimisticTask(newTodo, optimisticNewTodo, []);

useOptimisticTask is useful when encapsulating business aware hooks.