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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@dmrk/use-context-selector

v0.1.6

Published

Lightweight React library for context with fine-grained selector-based subscriptions, preventing unnecessary re-renders

Readme

use-context-selector

A lightweight React library for creating context with fine-grained selector-based subscriptions, preventing unnecessary re-renders.

Table of Contents

Features

  • 🎯 Selector-based subscriptions - Components only re-render when their selected values change
  • Performance optimized - Efficient updates with minimal re-renders
  • 🔒 Type-safe - Full TypeScript support with type inference
  • 🪶 Lightweight - Minimal dependencies, small bundle size
  • 🎨 Simple API - Easy to use with familiar React patterns
  • 🛠️ Custom equality functions - Use built-in shallow or any custom equality function (e.g., zustand/shallow)

Installation

pnpm add @dmrk/use-context-selector

Quick Start

import { createStore, createUseStore } from '@dmrk/use-context-selector';

// 1. Create your store
const store = createStore({
  count: 0,
  name: 'John',
});

// 2. Create a custom hook (optional but recommended)
const useStore = createUseStore(store);

// 3. Wrap your app with the Provider
function App() {
  return (
    <store.Provider>
      <Counter />
      <Name />
    </store.Provider>
  );
}

// 4. Use selectors in your components
function Counter() {
  const count = useStore(state => state.count);
  // ✅ Only re-renders when count changes
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => store.set({ count: count + 1 })}>Increment</button>
    </div>
  );
}

function Name() {
  const name = useStore(state => state.name);
  // ✅ Only re-renders when name changes
  return <p>Name: {name}</p>;
}

// When you update count:
store.set({ count: 1 });
// ✅ Only Counter re-renders, Name does not!

Note: For non-primitive selectors (objects/arrays), use a custom equality function like shallow or zustand/shallow to prevent unnecessary re-renders.

API Reference

createStore<State>(initialValue)

Creates a new context store with the given initial state.

Parameters:

  • initialValue: The initial state object

Returns: An object containing:

  • Provider: React component to wrap your app
  • context: The React context (for advanced usage)
  • get(): Function to get current state
  • set(partial | updater): Function to update state. Accepts either:
    • A partial state object: set({ count: 10 })
    • An updater function: set((state) => ({ count: state.count + 1 }))
  • subscribe(): Function to subscribe to state changes (for advanced usage)

Example:

const store = createStore({
  user: { name: 'Alice', age: 25 },
  theme: 'dark',
});

// Update with object
store.set({ theme: 'light' });

// Update with function (useful when update depends on current state)
store.set(state => ({
  user: { ...state.user, age: state.user.age + 1 },
}));

createUseStore(store)

Creates a custom hook for the given store with a cleaner API.

Parameters:

  • store: A store created by createStore

Returns: A hook function that accepts:

  • selector: Function to select a value from state
  • equalityFn (optional): Custom equality function. Defaults to Object.is. Use shallow or zustand/shallow for objects/arrays.

Example:

import shallow from '@dmrk/use-context-selector/shallow';

const useStore = createUseStore(store);

function MyComponent() {
  const userName = useStore(state => state.user.name);
  const user = useStore(state => state.user, shallow);
  return <div>{userName}</div>;
}

useStoreSelector(context, selector, equalityFn?)

Low-level hook for using context with selectors. Use createUseStore for a better API.

Parameters:

  • context: The React context from the store
  • selector: Function to select a value from state
  • equalityFn (optional): Custom equality function. Defaults to Object.is.

Returns: The selected value

Example:

import shallow from '@dmrk/use-context-selector/shallow';

function MyComponent() {
  const count = useStoreSelector(store.context, state => state.count);
  const user = useStoreSelector(store.context, state => state.user, shallow);
  return <div>{count}</div>;
}

InferState<T>

Type utility to extract the State type from a store instance.

import type { InferState } from '@dmrk/use-context-selector';

const store = createStore({ count: 0, name: 'John' });
type StoreState = InferState<typeof store>; // { count: number; name: string }

Advanced Usage

Derived Values

You can compute derived values in your selectors:

const useStore = createUseStore(store);

function DoubledCounter() {
  const doubled = useStore(state => state.count * 2);
  return <div>Doubled: {doubled}</div>;
}

Complex Selectors

Select nested values or combine multiple values:

const store = createStore({
  user: { name: 'Alice', age: 25 },
  settings: { theme: 'dark', language: 'en' },
});

const useStore = createUseStore(store);

function UserInfo() {
  const userAge = useStore(state => state.user.age);
  const theme = useStore(state => state.settings.theme);

  return <div className={theme}>User age: {userAge}</div>;
}

Updating State

The set method accepts either a partial state object or an updater function:

// Partial updates
store.set({ count: 10 });

// Function form (recommended when update depends on current state)
store.set(state => ({ count: state.count + 1 }));

// Update from component
function UpdateButton() {
  const count = useStore(state => state.count);
  return (
    <button onClick={() => store.set(state => ({ count: state.count + 1 }))}>
      Increment
    </button>
  );
}

Direct State Access

Access state directly without subscribing:

// Get current state
const currentState = store.get();

// Useful for event handlers or effects
function handleClick() {
  const current = store.get();
  console.log('Current count:', current.count);
  store.set({ count: current.count + 1 });
}

Best Practices

  • Use equality functions for non-primitive selectors: When selecting objects or arrays, use shallow or zustand/shallow to prevent unnecessary re-renders.
  • Select specific values when possible: Prefer selecting individual fields over entire objects when you only need a few values.

Common Pitfalls

  • Returning new objects/arrays without equality function: Selectors that return new references cause unnecessary re-renders. Use shallow or select individual values.

TypeScript Support

Full type inference and type safety:

const store = createStore({
  user: { name: 'Alice', age: 25 },
  count: 0,
});

const useStore = createUseStore(store);

function MyComponent() {
  // ✅ TypeScript infers return types
  const userName = useStore(state => state.user.name); // string
  const count = useStore(state => state.count); // number

  // ❌ TypeScript error - invalid property
  // const invalid = useStore(state => state.invalid);

  return <div>{userName}</div>;
}

Use InferState<T> to extract the state type from a store instance.

Comparison with Other Solutions

vs React Context + useContext

Standard Context:

  • ❌ All consumers re-render on any state change
  • ❌ Requires manual optimization with useMemo/memo
  • ✅ Built into React

use-context-selector:

  • ✅ Only re-renders when selected values change
  • ✅ Automatic optimization
  • ✅ Simpler API for complex state

vs Zustand

Zustand:

  • ✅ More features (middleware, devtools, etc.)
  • ✅ Can be used outside React
  • ❌ Larger bundle size
  • ❌ More complex API

use-context-selector:

  • ✅ Smaller bundle size
  • ✅ Simpler API
  • ✅ Better for React-only projects
  • ✅ Uses React Context (familiar pattern)
  • ❌ Fewer features (for now)

Requirements

  • React 18.0.0 or higher

License

ISC

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Author

dmrk