restate / v1.0.0

Get started

Install restate, share your first value between components, and use the same store outside React.

On this pageInstallYour first shared stateUpdate the valueUse it outside ReactTypeScriptReact NativeOne declaration on every platform

Install

restate works with React 16.8 and later. TypeScript declarations are included, and there are no other runtime dependencies.

Terminal
npm install @kkwaenggwari/restate

Your first shared state

Create the store once, outside your components. The value restate returns is both a hook and an object with methods such as set and get.

Editor and CharacterCount have no props or Provider between them. Typing in one updates the other.

JavaScript / JSX
import { restate } from '@kkwaenggwari/restate';

export const useDraft = restate('');

export function Editor() {
  const text = useDraft();
  return <textarea value={text} onChange={(event) => useDraft.set(event.target.value)} />;
}

export function CharacterCount() {
  const count = useDraft((text) => text.length);
  return <span>{count} characters</span>;
}

Update the value

set accepts a new value or a function of the previous value. reset returns to the value you declared.

Treat the value as immutable: return a new object or array instead of changing the old one, so selectors can see the change.

You push into cart.items and call useCart.set(cart). Why does nothing re-render?

The store receives the same object, and Object.is reports no change. Return a new object, for example useCart.set(cart => ({ ...cart, items: [...cart.items, item] })).

JavaScript / JSX
useCount.set(10); // replace the value
useCount.set((count) => count + 1); // compute from the previous value
useCount.reset(); // back to the declared initial value

Use it outside React

The same store works in event handlers, services and tests. get reads the current value, and subscribe calls you after each change and returns a function that stops listening.

JavaScript / JSX
import { useCart } from './stores/cart';

// Any module, event handler or test can use the same store.
const current = useCart.get();
useCart.set((cart) => ({ ...cart, items: [...cart.items, 'Pen'] }));

const stop = useCart.subscribe((cart, previous) => {
  console.log(previous.items.length, '→', cart.items.length);
});
stop();

TypeScript

Pass the state type once. Selectors, set and every method are typed from it.

JavaScript / JSX
import { restate } from '@kkwaenggwari/restate';

type Cart = { items: string[]; coupon: string };

export const useCart = restate<Cart>({ items: [], coupon: '' });

const count = useCart((cart) => cart.items.length); // number
useCart.set((cart) => ({ ...cart, coupon: 'SPRING' }));

React Native

Memory stores need nothing else on React Native. To save state, install react-native-mmkv; the React Native entry loads it automatically.

For bare projects, run pod install for iOS after installing. In Expo, use a development build because MMKV is a native module.

Terminal
npm install @kkwaenggwari/restate react-native-mmkv@4 react-native-nitro-modules

One declaration on every platform

A saved store uses IndexedDB in the browser and MMKV on React Native. The declaration and your components stay the same.

JavaScript / JSX
import { persistedRestate } from '@kkwaenggwari/restate';

// IndexedDB on the web, MMKV on React Native. Same declaration.
export const useDraft = persistedRestate('', { key: 'draft' });

Search docs

Search titles, descriptions and text of every guide.