Which is Better React State Management Libraries?
use-context-selector vs constate
1 Year
use-context-selectorconstate
What's React State Management Libraries?

In the realm of React development, effective state management is crucial for building scalable and maintainable applications. Both 'constate' and 'use-context-selector' provide unique solutions for managing state in React applications, focusing on performance and simplicity. 'constate' simplifies the way context is used by allowing developers to create a context and its provider in a more straightforward manner, while 'use-context-selector' enhances context usage by enabling selective re-renders, thus optimizing performance. These libraries cater to different needs in state management, making them valuable tools for React developers.

NPM Package Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
use-context-selector348,4322,68643.1 kB46 months agoMIT
constate98,9363,93020.7 kB9-MIT
Feature Comparison: use-context-selector vs constate

Simplicity

  • use-context-selector: Use-context-selector provides a more complex API that allows for selective context updates. While it may require a deeper understanding of context, it offers powerful capabilities for optimizing performance in larger applications.
  • constate: Constate offers a very simple API that allows developers to create context and provider components with minimal boilerplate. This makes it easy to set up and use, especially for smaller applications or when rapid development is needed.

Performance Optimization

  • use-context-selector: Use-context-selector shines in performance optimization by allowing components to subscribe to specific parts of the context. This means that only components that depend on the changed context will re-render, significantly improving performance in larger applications.
  • constate: While constate is efficient, it does not inherently prevent unnecessary re-renders. Developers need to manage state updates carefully to avoid performance issues as the application scales.

Learning Curve

  • use-context-selector: Use-context-selector has a steeper learning curve due to its advanced features. Developers need to understand how to effectively use selectors to benefit from the performance improvements it offers.
  • constate: Constate has a gentle learning curve, making it accessible for developers who are new to React context. Its straightforward approach allows for quick onboarding and implementation.

Extensibility

  • use-context-selector: Use-context-selector is more extensible, allowing developers to create complex state management solutions by combining it with other hooks and libraries, making it suitable for larger and more complex applications.
  • constate: Constate is designed to be minimalistic and does not provide extensive built-in features for extensibility. However, it can be easily integrated with other libraries and tools in the React ecosystem.

Use Cases

  • use-context-selector: Use-context-selector is ideal for larger applications where performance is critical. It is particularly useful when you need to manage state across many components without causing unnecessary re-renders.
  • constate: Constate is best suited for smaller applications or components where simplicity and quick setup are essential. It is ideal for projects that do not require complex state management.
How to Choose: use-context-selector vs constate
  • use-context-selector: Opt for 'use-context-selector' if your application requires fine-grained control over context updates to optimize performance. This package is particularly beneficial for larger applications where reducing unnecessary re-renders is critical.
  • constate: Choose 'constate' if you prefer a straightforward and minimalistic approach to context management in React. It is ideal for applications where simplicity and ease of use are prioritized, allowing you to quickly set up context without boilerplate code.
README for use-context-selector

use-context-selector

CI npm size discord

React useContextSelector hook in userland

Introduction

React Context and useContext is often used to avoid prop drilling, however it's known that there's a performance issue. When a context value is changed, all components that useContext will re-render.

To solve this issue, useContextSelector is proposed and later proposed Speculative Mode with context selector support. This library provides the API in userland.

Prior to v1.3, it uses changedBits=0 feature to stop propagation, v1.3 no longer depends on this undocumented feature.

Install

This package requires some peer dependencies, which you need to install by yourself.

npm install use-context-selector react scheduler

Notes for library authors:

Please do not forget to keep "peerDependencies" and note instructions to let users to install peer dependencies.

Technical memo

To make it work like original React context, it uses useReducer cheat mode intentionally.

It also requires useContextUpdate to behave better in concurrent rendering. Its usage is optional and only required if the default behavior is unexpected.

If you need a simpler solution, you can use useSyncExternalStore without any libraries. See an example.

Usage

import { useState } from 'react';
import { createRoot } from 'react-dom/client';

import { createContext, useContextSelector } from 'use-context-selector';

const context = createContext(null);

const Counter1 = () => {
  const count1 = useContextSelector(context, (v) => v[0].count1);
  const setState = useContextSelector(context, (v) => v[1]);
  const increment = () =>
    setState((s) => ({
      ...s,
      count1: s.count1 + 1,
    }));
  return (
    <div>
      <span>Count1: {count1}</span>
      <button type="button" onClick={increment}>
        +1
      </button>
      {Math.random()}
    </div>
  );
};

const Counter2 = () => {
  const count2 = useContextSelector(context, (v) => v[0].count2);
  const setState = useContextSelector(context, (v) => v[1]);
  const increment = () =>
    setState((s) => ({
      ...s,
      count2: s.count2 + 1,
    }));
  return (
    <div>
      <span>Count2: {count2}</span>
      <button type="button" onClick={increment}>
        +1
      </button>
      {Math.random()}
    </div>
  );
};

const StateProvider = ({ children }) => (
  <context.Provider value={useState({ count1: 0, count2: 0 })}>
    {children}
  </context.Provider>
);

const App = () => (
  <StateProvider>
    <Counter1 />
    <Counter2 />
  </StateProvider>
);

createRoot(document.getElementById('app')).render(<App />);

API

createContext

This creates a special context for useContextSelector.

Parameters

  • defaultValue Value

Examples

import { createContext } from 'use-context-selector';

const PersonContext = createContext({ firstName: '', familyName: '' });

useContextSelector

This hook returns context selected value by selector.

It will only accept context created by createContext. It will trigger re-render if only the selected value is referentially changed.

The selector should return referentially equal result for same input for better performance.

Parameters

  • context Context<Value>
  • selector function (value: Value): Selected

Examples

import { useContextSelector } from 'use-context-selector';

const firstName = useContextSelector(PersonContext, (state) => state.firstName);

useContext

This hook returns the entire context value. Use this instead of React.useContext for consistent behavior.

Parameters

  • context Context<Value>

Examples

import { useContext } from 'use-context-selector';

const person = useContext(PersonContext);

useContextUpdate

This hook returns an update function to wrap an updating function

Use this for a function that will change a value in concurrent rendering in React 18. Otherwise, there's no need to use this hook.

Parameters

  • context Context<Value>

Examples

import { useContextUpdate } from 'use-context-selector';

const update = useContextUpdate();

// Wrap set state function
update(() => setState(...));

// Experimental suspense mode
update(() => setState(...), { suspense: true });

BridgeProvider

This is a Provider component for bridging multiple react roots

Parameters

  • $0 {context: Context<any>, value: any, children: ReactNode}

    • $0.context
    • $0.value
    • $0.children

Examples

const valueToBridge = useBridgeValue(PersonContext);
return (
  <Renderer>
    <BridgeProvider context={PersonContext} value={valueToBridge}>
      {children}
    </BridgeProvider>
  </Renderer>
);

useBridgeValue

This hook return a value for BridgeProvider

Parameters

  • context Context<any>

Limitations

  • In order to stop propagation, children of a context provider has to be either created outside of the provider or memoized with React.memo.
  • Provider trigger re-renders only if the context value is referentially changed.
  • Neither context consumers or class components are supported.
  • The stale props issue can't be solved in userland.
  • Tearing is only avoided if all consumers get data using useContextSelector. If you use both props and use-context-selector to pass the same data, they may provide inconsistence data for a brief moment. (02_tearing_spec fails)

Examples

The examples folder contains working examples. You can run one of them with

PORT=8080 yarn run examples:01_counter

and open http://localhost:8080 in your web browser.

You can also try them in codesandbox.io: 01 02 03

Projects that use use-context-selector