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

keydux

v0.0.6

Published

Keydux is a lightweight shared state management library for React that offers a streamlined alternative to Redux and other state management libraries.

Readme

keydux

Keydux is a lightweight shared state management library for React that offers a streamlined alternative to Redux and other state management libraries.

Keydux provides hooks for a minimalistic API for reading, updating, and watching state changes across your application. Unlike the Context API, updates only rerender the components that hook into each state key, not the entire component tree under the provider. Keydux reduces boilerplate while delivering the performance optimizations, type safety, and flexibility you would get from Redux, other state management libraries, and other handrolled solutions.

Features

  • Simple Shared State: Easily create and use shared state without the complexities of Redux.
  • Hook-Based API: Use simple React hooks (useSharedState) to access and modify your state.
  • Debounced Updates: Prevent excessive re-renders by debouncing state updates.
  • Avoids Context API pitfalls Unlike Context API, developers don't need to constantly search for context providers in their true or worry about global rerenders
  • Persistent Storage: Optionally save state changes to localStorage (or a fallback) with minimal configuration.
  • Type Safety: Fully typed with TypeScript to ensure reliable state management.
  • No Dependencies: keydux has no dependencies other than React (a peer dependency)
  • Lightweight: keydux is extremely lightweight -- 1kb minified and gzipped, 75% smaller than Redux

Installation

You can install keydux via npm or yarn:

npm install keydux
# or
yarn add keydux

Usage

Setting Up the Provider

Wrap your entire application with the SharedStateProvider to enable shared state management:

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { SharedStateProvider } from "keydux/src/SharedStateProvider";

ReactDOM.render(
  <SharedStateProvider>
    <App />
  </SharedStateProvider>,
  document.getElementById("root")
);

Creating a Shared State

Use the useSharedState hook to manage a shared piece of state. The hook provides:

  • value: the current value.
  • debouncedValue: the value after applying a debounce delay.
  • setValue: a function to update the state.
  • clear: a helper function to reset the state to its initial value.

Example: A Counter with Storage and Debouncing

import React from "react";
import { useSharedState } from "keydux/src/useSharedState";

const useCounter = () => {
  return useSharedState({
    key: "counter",
    initialValue: 0,
    debounceTime: 1000,
  });
}

function Counter() {
  const { setValue: setCount, value: count, clear } = useCounter()

  return (
    <div>
      <h1>Counter: {count}</h1>
      <button onClick={() => setCount(count => count + 1)}>Increment</button>
      <button onClick={clear}>Reset</button>
      <CounterDisplay />
    </div>
  );
}

function CounterDisplay() {
  const { value: count, debouncedValue } = useCounter()

  return (
    <>
      <div>Counter: {count}</div>
      <div>Debounced Counter: {debouncedValue}</div>
    </>
  );
}

export default Counter;

Adding Type Safety

keydux is written in TypeScript, so you can easily enforce type safety by providing an explicit type for your state values. This helps catch errors at compile time and provides better autocompletion. You can also use the createUseSharedState function to provide type safety for your state key values.

import React from "react";
import { createUseSharedState } from "keydux/src/useSharedState";

enum STATE_KEY {
  USER_PROFILE = "userProfile",
}

type UserProfile = {
  name: string;
  age: number;
};

const useSharedState = createUseSharedState<STATE_KEY>()

function UserProfile() {
  const { value: userProfile, setValue } = useSharedState<UserProfile>({
    key: STATE_KEY.USER_PROFILE,
    initialValue: { name: "John Doe", age: 30 },
  });

  const updateName = () => {
    setValue({ ...userProfile, name: "Jane Doe" });
  };

  return (
    <div>
      <h2>{user.name}</h2>
      <p>Age: {user.age}</p>
      <button onClick={updateName}>Change Name</button>
    </div>
  );
}

export default UserProfile;

Debouncing State Updates

Avoid performance issues through debouncing, which delays the propagation of state changes until the specified time has elapsed. This is especially useful when reacting to fast-changing input, such as text inputs:

import React from "react";
import { useSharedState } from "keydux;



function SearchInput() {
  const {
    value: searchTerm,
    debouncedValue: debouncedSearchTerm,
    setValue: setSearchTerm
  } = useSharedState<string>({
    key: "searchTerm",
    initialValue: "",
    debounceTime: 500, // wait 500ms after the last change to update debouncedValue
  });

  useEffect(() => {
    // Fire my API call with the debounced value
  }, [debouncedSearchTerm])

  return (
    <div>
      <input
        type="text"
        value={searchTerm}
        onChange={(e) => setSearchTerm(e.target.value)}
        placeholder="Type to search..."
      />
    </div>
  );
}

export default SearchInput;

Saving State to Storage

To persist state changes (for example, between page reloads), enable storage support by setting shouldSaveToStorage to true. keydux utilizes a storage adapter that defaults to localStorage (with a fallback if not in the browser):

import React from "react";
import { useSharedState } from "keydux/src/useSharedState";

function TodoList() {
  const { value: todos, setValue, clear } = useSharedState<string[]>({
    key: "todos",
    initialValue: [],
    shouldSaveToStorage: true, // persist todos in storage
  });

  const addTodo = (todo: string) => {
    setValue([...todos, todo]);
  };

  return (
    <div>
      <h2>Todo List</h2>
      <button onClick={() => addTodo("New Todo")}>Add Todo</button>
      <button onClick={clear}>Clear Todos</button>
      <ul>
        {todos.map((todo, idx) => (
          <li key={idx}>{todo}</li>
        ))}
      </ul>
    </div>
  );
}

export default TodoList;

Updatng state outside of React

You can also update state outside of React by instantiating a StateManager instance and passing it to the SharedStateProvider.

The StateManager instance has read and write methods that can be call directy to access and update state outside of React

import { StateManager } from "keydux";
import { router } from "./router";
import { STATE_KEY } from "./constants";

const stateManager = new StateManager()

router.on("beforeNavigate", () => {
  stateManager.write(STATE_KEY.COUNTER, 0)
})

const MyApp = () => {
  return (
    <SharedStateProvider stateManager={stateManager}>
      <App />
    </SharedStateProvider>
  )
}

Comparison to Redux

While Redux is a powerful state management library, it comes with its own set of complexities and boilerplate. keydux offers a simpler, hook-based approach.

In practice, redux usage often involves basic state management -- ie getters and setters -- complicated by a whole lot of indirection and boilerplate.

In contract, keydux gets to the meat of your usage without all the headaches.

| Feature | keydux | Redux | |-----------------------|-------------------------------------------------|--------------------------------------------------------| | Boilerplate | Minimal setup with a provider and hooks | Requires explicit reducers, actions, and middleware | | API Style | Simple, hook-driven API | Action dispatch, reducers, and middleware chaining | | Debouncing Support| Built-in with useDebouncedValue | Needs external libraries or custom implementation | | Local Persistence | Built-in with shouldSaveToStorage | Must be implemented separately | | Type Safety | Full TypeScript integration out-of-the-box | Available but requires additional configuration | | Browser Devtools | Available and easy to install | Available and easy to install |

Conclusion

keydux provides an effortless way to manage shared state in React applications with built-in support for debouncing, localStorage persistence, and type safety. It's ideal for projects looking for a practical, less verbose state management solution compared to Redux.

License

MIT