Convert Figma logo to code with AI

diegohaz logoconstate

React Context + State

3,952
91
3,952
9

Top Related Projects

19,629

Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features of React.

48,653

🐻 Bear necessities for state management in React

60,936

A JS library for predictable global state management

27,618

Simple, scalable state management.

Quick Overview

Constate is a lightweight and flexible state management library for React that uses React Context API. It provides a simple and intuitive way to manage global state in React applications, without the need for complex state management solutions like Redux or MobX.

Pros

  • Simplicity: Constate has a minimal API and is easy to understand and use, making it a great choice for small to medium-sized React projects.
  • Flexibility: Constate allows you to create and manage state in a modular way, making it easy to scale your application as it grows.
  • Performance: Constate uses the React Context API, which is optimized for performance and avoids unnecessary re-renders.
  • No Boilerplate: Constate eliminates the need for boilerplate code that is often required in other state management solutions.

Cons

  • Limited Ecosystem: Constate is a relatively new library, and the ecosystem of third-party tools and plugins is not as extensive as some other state management solutions.
  • Lack of Tooling: Constate does not have the same level of tooling and debugging support as some other state management solutions, which can make it more difficult to work with in larger projects.
  • Learning Curve: While Constate is relatively simple to use, developers who are new to the React Context API may still need to invest some time in learning how to use it effectively.
  • Lack of Middleware: Constate does not provide built-in support for middleware, which can be useful for implementing features like logging, error handling, or performance optimization.

Code Examples

Here are a few examples of how to use Constate in a React application:

Creating a simple counter state:

import { createState } from 'constate';

const [useCounter, { increment, decrement }] = createState(() => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}));

Consuming the counter state in a component:

import { useCounter } from './counter';

function CounterComponent() {
  const { count, increment, decrement } = useCounter();

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}

Combining multiple states:

import { createState } from 'constate';

const [useUserState, { setUser }] = createState(() => ({
  user: null,
  setUser: (user) => set({ user }),
}));

const [useThemeState, { setTheme }] = createState(() => ({
  theme: 'light',
  setTheme: (theme) => set({ theme }),
}));

const [useAppState] = createState(() => ({
  ...useUserState(),
  ...useThemeState(),
}));

Getting Started

To get started with Constate, you can follow these steps:

  1. Install the library using npm or yarn:
npm install constate
  1. Create a new state using the createState function:
import { createState } from 'constate';

const [useCounter, { increment, decrement }] = createState(() => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}));
  1. Use the state in your React components:
import { useCounter } from './counter';

function CounterComponent() {
  const { count, increment, decrement } = useCounter();

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}
  1. Combine multiple states using the createState function:
import

Competitor Comparisons

19,629

Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features of React.

Pros of Recoil

  • Offers a more flexible and scalable state management solution for complex React applications
  • Provides built-in support for asynchronous data fetching and derived state
  • Enables fine-grained updates and optimizations through atom-based state management

Cons of Recoil

  • Steeper learning curve due to its unique concepts and API
  • Requires more boilerplate code for setting up atoms and selectors
  • Still in experimental phase, which may lead to API changes and potential instability

Code Comparison

Recoil:

import { atom, useRecoilState } from 'recoil';

const counterState = atom({
  key: 'counterState',
  default: 0,
});

function Counter() {
  const [count, setCount] = useRecoilState(counterState);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

Constate:

import React from 'react';
import constate from 'constate';

const [CounterProvider, useCounter] = constate(() => {
  const [count, setCount] = React.useState(0);
  return { count, setCount };
});

function Counter() {
  const { count, setCount } = useCounter();
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
48,653

🐻 Bear necessities for state management in React

Pros of zustand

  • Simpler API with less boilerplate
  • Built-in middleware support (e.g., persist, devtools)
  • Can be used outside of React components

Cons of zustand

  • Less type-safe compared to constate's TypeScript support
  • Doesn't leverage React's Context API, which may be preferred in some cases
  • Steeper learning curve for developers familiar with React's built-in state management

Code Comparison

constate:

const useCounter = createState(useState(0));
const [Counter, CounterProvider] = constate(useCounter);

function App() {
  return (
    <CounterProvider>
      <Counter />
    </CounterProvider>
  );
}

zustand:

const useStore = create(set => ({
  count: 0,
  increment: () => set(state => ({ count: state.count + 1 }))
}));

function Counter() {
  const count = useStore(state => state.count);
  const increment = useStore(state => state.increment);
  return <button onClick={increment}>{count}</button>;
}

Both libraries aim to simplify state management in React applications, but they take different approaches. constate builds upon React's Context API, making it more familiar to React developers, while zustand provides a standalone state management solution with a focus on simplicity and flexibility.

60,936

A JS library for predictable global state management

Pros of Redux

  • Robust ecosystem with extensive middleware and developer tools
  • Predictable state management with a single source of truth
  • Well-suited for large-scale applications with complex state logic

Cons of Redux

  • Steeper learning curve and more boilerplate code
  • Can be overkill for smaller applications or simpler state management needs
  • Requires careful consideration of performance optimizations for large state trees

Code Comparison

Redux:

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    default:
      return state;
  }
};

Constate:

const useCounter = () => {
  const [count, setCount] = useState(0);
  const increment = () => setCount(count + 1);
  return { count, increment };
};

Redux offers a more structured approach with actions and reducers, while Constate leverages React's built-in hooks for simpler state management. Redux is better suited for complex state logic, while Constate provides a more lightweight solution for component-level state management.

27,618

Simple, scalable state management.

Pros of MobX

  • More powerful and feature-rich state management solution
  • Supports complex scenarios with computed values and reactions
  • Better performance for large-scale applications with many state updates

Cons of MobX

  • Steeper learning curve due to its complexity and concepts
  • Requires more boilerplate code for setup and configuration
  • May be overkill for simple applications or components

Code Comparison

MobX:

import { makeAutoObservable } from "mobx";

class Timer {
  secondsPassed = 0;
  constructor() {
    makeAutoObservable(this);
  }
  increase() {
    this.secondsPassed += 1;
  }
}

Constate:

import React from "react";
import constate from "constate";

const [CounterProvider, useCounter] = constate(() => {
  const [count, setCount] = React.useState(0);
  const increment = () => setCount(prevCount => prevCount + 1);
  return { count, increment };
});

MobX offers a more robust solution for complex state management scenarios, while Constate provides a simpler, React-focused approach using hooks and context. MobX is better suited for large applications with intricate state interactions, whereas Constate is ideal for smaller projects or components that require lightweight state management.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

constate logo

Constate

NPM version NPM downloads Size Dependencies GitHub Workflow Status (branch) Coverage Status

Write local state using React Hooks and lift it up to React Context only when needed with minimum effort.


🕹 CodeSandbox demos 🕹
Counter I18n Theming TypeScript Wizard Form

Basic example

import React, { useState } from "react";
import constate from "constate";

// 1️⃣ Create a custom hook as usual
function useCounter() {
  const [count, setCount] = useState(0);
  const increment = () => setCount(prevCount => prevCount + 1);
  return { count, increment };
}

// 2️⃣ Wrap your hook with the constate factory
const [CounterProvider, useCounterContext] = constate(useCounter);

function Button() {
  // 3️⃣ Use context instead of custom hook
  const { increment } = useCounterContext();
  return <button onClick={increment}>+</button>;
}

function Count() {
  // 4️⃣ Use context in other components
  const { count } = useCounterContext();
  return <span>{count}</span>;
}

function App() {
  // 5️⃣ Wrap your components with Provider
  return (
    <CounterProvider>
      <Count />
      <Button />
    </CounterProvider>
  );
}

Learn more

Advanced example

import React, { useState, useCallback } from "react";
import constate from "constate";

// 1️⃣ Create a custom hook that receives props
function useCounter({ initialCount = 0 }) {
  const [count, setCount] = useState(initialCount);
  // 2️⃣ Wrap your updaters with useCallback or use dispatch from useReducer
  const increment = useCallback(() => setCount(prev => prev + 1), []);
  return { count, increment };
}

// 3️⃣ Wrap your hook with the constate factory splitting the values
const [CounterProvider, useCount, useIncrement] = constate(
  useCounter,
  value => value.count, // becomes useCount
  value => value.increment // becomes useIncrement
);

function Button() {
  // 4️⃣ Use the updater context that will never trigger a re-render
  const increment = useIncrement();
  return <button onClick={increment}>+</button>;
}

function Count() {
  // 5️⃣ Use the state context in other components
  const count = useCount();
  return <span>{count}</span>;
}

function App() {
  // 6️⃣ Wrap your components with Provider passing props to your hook
  return (
    <CounterProvider initialCount={10}>
      <Count />
      <Button />
    </CounterProvider>
  );
}

Learn more

Installation

npm:

npm i constate

Yarn:

yarn add constate

API

constate(useValue[, ...selectors])

Constate exports a single factory method. As parameters, it receives useValue and optional selector functions. It returns a tuple of [Provider, ...hooks].

useValue

It's any custom hook:

import { useState } from "react";
import constate from "constate";

const [CountProvider, useCountContext] = constate(() => {
  const [count] = useState(0);
  return count;
});

You can receive props in the custom hook function. They will be populated with <Provider />:

const [CountProvider, useCountContext] = constate(({ initialCount = 0 }) => {
  const [count] = useState(initialCount);
  return count;
});

function App() {
  return (
    <CountProvider initialCount={10}>
      ...
    </CountProvider>
  );
}

The API of the containerized hook returns the same value(s) as the original, as long as it is a descendant of the Provider:

function Count() {
  const count = useCountContext();
  console.log(count); // 10
}

selectors

Optionally, you can pass in one or more functions to split the custom hook value into multiple React Contexts. This is useful so you can avoid unnecessary re-renders on components that only depend on a part of the state.

A selector function receives the value returned by useValue and returns the value that will be held by that particular Context.

import React, { useState, useCallback } from "react";
import constate from "constate";

function useCounter() {
  const [count, setCount] = useState(0);
  // increment's reference identity will never change
  const increment = useCallback(() => setCount(prev => prev + 1), []);
  return { count, increment };
}

const [Provider, useCount, useIncrement] = constate(
  useCounter,
  value => value.count, // becomes useCount
  value => value.increment // becomes useIncrement
);

function Button() {
  // since increment never changes, this will never trigger a re-render
  const increment = useIncrement();
  return <button onClick={increment}>+</button>;
}

function Count() {
  const count = useCount();
  return <span>{count}</span>;
}

Contributing

If you find a bug, please create an issue providing instructions to reproduce it. It's always very appreciable if you find the time to fix it. In this case, please submit a PR.

If you're a beginner, it'll be a pleasure to help you contribute. You can start by reading the beginner's guide to contributing to a GitHub project.

When working on this codebase, please use yarn. Run yarn examples to run examples.

License

MIT © Diego Haz

NPM DownloadsLast 30 Days