restate / v1.0.0

何时保存由你决定

把 store 保存到 IndexedDB 或 MMKV,启动时加载一次,显式或自动保存,并显示未保存的修改。

本页内容声明持久化 store启动时只等待一次保存、撤销修改与重置显示未保存的修改和进度动手试试自动保存页面关闭之前处理存储错误

声明持久化 store

把 restate 换成 persistedRestate 并传入 key。组件继续使用同一个 Hook 和 set。

创建后会自动恢复已保存的值。编辑只改变内存;在你保存或开启 autoSave 之前不会写入任何内容。

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

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

启动时只等待一次

在客户端入口导入应用及其 store,然后在渲染前等待 restateManager.ready。之后组件就能直接读取已保存的值。

存储不可用(例如服务端渲染或浏览器禁用了存储)不算失败:这些 store 会在内存中工作。只有当记录无法读取、迁移或校验时,ready 才会被拒绝。

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 表示正在执行的存储操作。

传入 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 } 会等到变化停顿。

连续的变化会合并为一次写入,改回已保存的值则不写入。失败会显示在 status().error 中。组件拥有的 scope 在卸载时会写入待处理的修改。

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 被拒绝。每个 restate 错误都有 code,持久化 store 的错误还带有记录的 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'}".`);
}

搜索文档

搜索所有指南的标题、描述和正文。