JSPM

  • Created
  • Published
  • Downloads 147109
  • Score
    100M100P100Q172521F
  • License MIT

Yet another React state management library that lets you work with local state and scale up to global state with ease

Package Exports

  • constate

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (constate) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

constate logo


1 kB React state management library that lets you write contextual state
as if it were local state, using React Hooks.


NPM version Gzip size Dependencies Build Status Coverage Status


🎮 Play with CodeSandbox examples
Counter


import React from "react";
import { Provider, useContextState } from "constate";

function useCounter(context) {
  // replacing React.useState(0);
  const [count, setCount] = useContextState(context, 0);
  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count - 1);
  return { count, increment, decrement };
}

function DecrementButton() {
  const { decrement } = useCounter("counter1");
  return <button onClick={decrement}>-</button>;
}

function IncrementButton() {
  const { increment } = useCounter("counter1");
  return <button onClick={increment}>+</button>;
}

function Count() {
  const { count } = useCounter("counter1");
  return <span>{count}</span>
}

function App() {
  return (
    <Provider>
      <DecrementButton />
      <Count />
      <IncrementButton />
    </Provider>
  );
}

Table of Contents


Installation

npm i constate@next

Constate v1 is in alpha version. If you're looking for v0, see v0 docs or read the migration guide.


Provider

↑ Back to top

First, you should wrap your app (or the part using Constate) with Provider so as to access contextual state within hooks:

import React from "react";
import { Provider } from "constate";

function App() {
  return (
    <Provider devtools={process.env.NODE_ENV === "development"}>
      ...
    </Provider>
  );
}

Passing devtools prop to Provider will enable the redux-devtools-extension integration, if that's installed in your browser. With that, you can easily debug the state of your application.

Using Redux Devtools Extension


useContextState

↑ Back to top

useContextState has the same API as React.useState, except that it receives contextKey as the first argument.

import { useContextState } from "constate";

function Component() {
  // accesses state.contextKey in context
  const [state, setState] = useContextState("contextKey", "initialValue");
  ...
}

If you pass null or undefined into the contextKey parameter, it'll work exactly like React.useState:

import { useContextState } from "constate";

function Component() {
  // same as React.useState("initialValue")
  const [state, setState] = useContextState(null, "initialValue");
  ...
}

This means you can create custom hooks that can be either contextual or local depending on the component using it:

import React from "react";
import { useContextState } from "constate";

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

function ContextualCounter() {
  const { count, increment } = useCounter("counter1");
  return <button onClick={increment}>{count}</button>;
}

function LocalCounter() {
  const { count, increment } = useCounter();
  return <button onClick={increment}>{count}</button>;
}

useContextReducer

↑ Back to top

Just like useContextState, useContextReducer works similarly to React.useReducer, but accepting a contextKey argument:

import { useContextReducer } from "constate";

function reducer(state, action) {
  switch(action.type) {
    case "INCREMENT": return state + 1;
    case "DECREMENT": return state - 1;
    default: return state;
  }
}

function useCounter(context) {
  const [count, dispatch] = useContextReducer(context, reducer, 0);
  const increment = () => dispatch({ type: "INCREMENT" });
  const decrement = () => dispatch({ type: "DECREMENT" });
  return { count, increment, decrement };
}

function ContextualCounter() {
  const { count, increment } = useCounter("counter1");
  return <button onClick={increment}>{count}</button>;
}

createContext

↑ Back to top

If you want to set a initial state for the whole context tree and/or want to create separate contexts, you can use createContext:

// MyContext.js
import { createContext } from "constate";

const { Provider, useContextState, useContextReducer } = createContext({
  counter1: 0,
  posts: [
    { id: 1, title: "Hello World!" }
  ]
});

export { Provider, useContextState, useContextReducer };
// App.js
import React from "react";
import { Provider, useContextState } from "./MyContext";

function Counter() {
  // no need for initial value, it has been set in context
  const [count, setCount] = useContextState("counter1");
  const increment = () => setCount(count + 1);
  return <button onClick={increment}>{count}</button>;
}

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

When importing hooks directly from the constate package, you're, in fact, using a default context created by our index file.


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:start to run examples.


License

MIT © Diego Haz