restate / v1.0.0

保存は自分のタイミングで

ストアを IndexedDB や MMKV に保存し、起動時に一度だけ読み込み、明示的または自動で保存して、未保存の変更を表示します。

このページの内容保存ストアを宣言する起動時に一度だけ待つ保存、元に戻す、リセット未保存の変更と進行状況を表示する試してみる自動で保存するページを閉じる前にストレージのエラーを処理する

保存ストアを宣言する

restate を persistedRestate に置き換えて key を渡します。コンポーネントは同じフックと set をそのまま使います。

保存された値は作成後に自動で復元されます。編集で変わるのはメモリだけで、保存するか autoSave をオンにするまで何も書き込まれません。

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

export const useDraft = persistedRestate('', {
  key: 'article-draft',
  validate: (value) => typeof value === 'string',
});

起動時に一度だけ待つ

クライアントのエントリーでアプリとストアを import し、描画の前に restateManager.ready を待ちます。そうすればコンポーネントは保存された値をそのまま読めます。

サーバーレンダリング中やブラウザーにブロックされているときなど、ストレージが使えないことは失敗ではありません。そうしたストアはメモリ上で動きます。ready が reject されるのは、レコードを読み込めない、マイグレーションできない、または検証を通らないときだけです。

JavaScript / JSX
import { createRoot } from 'react-dom/client';
import { restateManager } from '@kkwaenggwari/restate';
import App from './App';

async function start() {
  const root = createRoot(document.getElementById('root'));
  try {
    await restateManager.ready;
    root.render(<App />);
  } catch (error) {
    root.render(<p>Could not load saved data.</p>);
    console.error(error);
  }
}
start();

保存、元に戻す、リセット

save は現在の値を書き込み、restore は保存済みの値に戻し、resetAll はメモリとストレージの両方をクリアします。どれも Promise を返します。

JavaScript / JSX
await useDraft.save(); // write the current value
await useDraft.restore(); // return to the saved value
await useDraft.resetAndClearStorage(); // initial value in memory, record removed

未保存の変更と進行状況を表示する

useStatus は永続化のステータスが変わると再レンダリングされます。dirty は、メモリが最後に読み込み・保存・復元した値と異なる間 true です。operation は実行中のストレージ操作の名前を示します。

1 つのフィールドが変わったときだけ再レンダリングするには、selectorを渡します。

JavaScript / JSX
function SaveButton() {
  const { dirty, operation, error } = useDraft.useStatus();
  const saving = operation === 'save';

  return (
    <>
      <button disabled={!dirty || saving} onClick={() => useDraft.save().catch(() => {})}>
        {saving ? 'Saving…' : 'Save'}
      </button>
      {error != null && <p>Could not save your draft.</p>}
    </>
  );
}

試してみる

入力し、ストレージの遅延を大きくして保存します。サンプルをもう一度再生すると、保存した下書きが復元されます。

サンプルを準備中…

自動で保存する

設定や下書きのように常に保存したい値は、一度オプトインするだけです。autoSave: true は変更のたびに保存し、{ delayMs } は変更が止まるまで待ちます。

連続した変更は 1 回の書き込みになり、保存済みの値に戻す変更では何も書き込みません。失敗は status().error に表示されます。コンポーネントが所有するスコープは、アンマウント時に保留中の変更を書き込みます。

JavaScript / JSX
export const useTheme = persistedRestate('light', { key: 'theme', autoSave: true });

export const useDraft = persistedRestate('', {
  key: 'article-draft',
  autoSave: { delayMs: 500 },
});

ページを閉じる前に

同じステータスを React の外でも読めます。未保存の変更があるときは離れる前に警告したり、ページが非表示になったときにすべて保存したりできます。

JavaScript / JSX
window.addEventListener('beforeunload', (event) => {
  if (useDraft.status().dirty) event.preventDefault();
});

window.addEventListener('pagehide', () => {
  restateManager.saveAll();
});

ストレージのエラーを処理する

ストレージのエラーは、その操作の Promise を reject します。restate のエラーにはすべて code があり、保存ストアの場合はレコードの key も付きます。

JavaScript / JSX
try {
  await useDraft.save();
} catch (error) {
  if (error.code === 'STORAGE_UNAVAILABLE') showNotice('Saving is off in this browser.');
  else if (error.code === 'STORAGE_VALUE_TOO_LARGE') showNotice('This draft is too large.');
  else showNotice(`Could not save "${error.key ?? 'draft'}".`);
}

ドキュメントを検索

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