restate / v1.0.0

はじめる

restate をインストールし、最初の値をコンポーネント間で共有して、同じストアを React の外でも使います。

このページの内容インストール最初の共有状態値を更新するReact の外で使うTypeScriptReact Nativeどのプラットフォームでも宣言はひとつ

インストール

restate は React 16.8 以降で動きます。TypeScript の型定義を同梱しており、ほかのランタイム依存はありません。

Terminal
npm install @kkwaenggwari/restate

最初の共有状態

ストアはコンポーネントの外で一度だけ作ります。restate が返す値はフックであり、同時に set や get などのメソッドを持つオブジェクトでもあります。

Editor と CharacterCount の間には props も Provider もありません。片方に入力すると、もう片方が更新されます。

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>;
}

値を更新する

set は新しい値か、前の値を受け取る関数を受け付けます。reset は宣言した値に戻します。

値はイミュータブルとして扱ってください。古いオブジェクトや配列を変更するのではなく新しいものを返すと、selectorが変更に気づけます。

cart.items に push してから useCart.set(cart) を呼びました。なぜ何も再レンダリングされないのでしょう?

ストアが受け取るのは同じオブジェクトなので、Object.is は変更なしと判断します。たとえば 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

React の外で使う

同じストアがイベントハンドラー、サービス、テストでも使えます。get は現在の値を読み、subscribe は変更のたびに呼び出され、購読を止める関数を返します。

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

状態の型を一度渡すだけ。selector、set、すべてのメソッドにその型が反映されます。

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

メモリのストアなら React Native で追加の準備は要りません。状態を保存するには react-native-mmkv をインストールしてください。React Native 用のエントリーが自動で読み込みます。

bare プロジェクトでは、インストール後に iOS 向けに pod install を実行します。Expo では、MMKV がネイティブモジュールのため development build を使ってください。

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

どのプラットフォームでも宣言はひとつ

保存ストアはブラウザーでは IndexedDB、React Native では MMKV を使います。宣言もコンポーネントも変わりません。

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

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

ドキュメントを検索

すべてのガイドのタイトル、説明、本文から検索します。