restate / v1.0.0

可靠性設計

當儲存空間緩慢、出錯或不存在時 restate 保證什麼,以及如何解讀它回報的錯誤。

本頁內容保證依序儲存動手試試載入失敗時儲存並關閉沒有可用的儲存空間驗證與遷移已儲存的資料自備儲存空間限制與逾時錯誤代碼

保證

這些行為屬於 1.0 合約的一部分,並由套件的測試涵蓋。

情況restate 的做法
連續多次儲存依 store 依序執行;在佇列中等待的儲存會寫入最新的值。
某筆紀錄載入失敗autoSave 和批次儲存會以 LOAD_FAILED 略過它;只有明確的 save() 能取代它。
儲存途中元件被卸載已要求的儲存會完成;之後對已銷毀 store 的寫入會被忽略。
儲存空間無法使用store 在記憶體中運作,status().available 為 false,儲存會被拒絕。
轉接器卡住操作在 operationTimeoutMs 之後逾時,後續工作會等到轉接器結束。
待處理的工作太多新的操作會以 QUEUE_FULL 被拒絕,而不是無限增加。

依序儲存

同一個 store 的操作絕不會重疊。在另一次儲存等待時發出的儲存會取用較新的值,所以就算每次變化都儲存,也能寫入最新狀態而不會塞滿佇列。

JavaScript / JSX
useDraft.set('A');
const first = useDraft.save(); // writes "A"
useDraft.set('B');
const second = useDraft.save(); // waits in the queue
useDraft.set('C');
const third = useDraft.save(); // joins the waiting save

await Promise.all([first, second, third]); // ['A', 'C', 'C'] — two writes

動手試試

讓儲存空間變慢、讓寫入失敗,或乾脆移除儲存空間。

正在準備範例…

載入失敗時

restateManager.ready 會以 BULK_OPERATION_FAILED 被拒絕,並列出每個失敗的 store。在那筆紀錄成功載入前,autoSave 和 saveAll 不會取代它,而是回報 LOAD_FAILED。

用 initialize() 重試以保留並儲存你的修改、呼叫 restore() 捨棄修改,或呼叫 save() 刻意覆寫該紀錄。

JavaScript / JSX
try {
  await restateManager.ready;
} catch (error) {
  // BULK_OPERATION_FAILED: one entry per store that could not load.
  for (const { store, error: cause } of error.failures) {
    console.error(store.key, cause.code);
  }
}

儲存並關閉

卸載前要求的儲存仍會完成,所以「儲存並關閉」的處理函式不需要等待。

JavaScript / JSX
function Document({ onClose }) {
  const useDraft = useRestateScope((scope) => persistedRestate('', { scope, key: 'draft' }));

  const saveAndClose = () => {
    useDraft.save(); // finishes even after this component unmounts
    onClose();
  };
  // …
}

沒有可用的儲存空間

伺服器端渲染與瀏覽器封鎖儲存空間,在啟動時都不算錯誤。檢查 available,告訴使用者修改只保留在記憶體中。

JavaScript / JSX
const { available } = useDraft.status();

if (!available) {
  // Server rendering or blocked browser storage: the store works in memory
  // and save() rejects with STORAGE_UNAVAILABLE.
  showNotice('Changes are kept until you close this tab.');
}

驗證與遷移已儲存的資料

version、migrate 和 validate 能保護你不受舊紀錄或損毀紀錄影響。validate 會在儲存前,以及還原或遷移後執行。

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

const useSettings = persistedRestate(
  { theme: 'system' },
  {
    key: 'settings',
    version: 2,
    migrate(value, from, to) {
      if (from === 1 && to === 2 && typeof value?.darkMode === 'boolean') {
        return { theme: value.darkMode ? 'dark' : 'light' };
      }
      throw new Error('Unsupported stored version');
    },
    validate: (value) => ['system', 'light', 'dark'].includes(value?.theme),
  },
);

自備儲存空間

任何具有 getItem、setItem 和 removeItem 的物件都可以。方法可以回傳值或 Promise;isAvailable 是選用的。

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

const sessionStorageAdapter = {
  isAvailable: () => typeof sessionStorage !== 'undefined',
  getItem: (key) => sessionStorage.getItem(key),
  setItem: (key, value) => sessionStorage.setItem(key, value),
  removeItem: (key) => sessionStorage.removeItem(key),
};

export const useFilters = persistedRestate(
  { query: '' },
  {
    key: 'filters',
    storage: sessionStorageAdapter,
  },
);

限制與逾時

調整單一操作可以執行多久、可以有多少操作排隊,以及值最大可以多大。

JavaScript / JSX
persistedRestate(value, {
  key: 'draft',
  operationTimeoutMs: 10_000, // default 30000
  maxPendingOperations: 64, // default 256
  maxStorageCharacters: 1_000_000,
});

錯誤代碼

restate 建立的錯誤名稱為 RestateError,帶有 code,持久化 store 的錯誤還帶有 key。儲存轉接器和你的回呼可能會以它們自己的錯誤拒絕。

代碼意義
BULK_OPERATION_FAILEDrestateManager.ready 或 saveAll 等批次呼叫發生失敗;請查看 error.failures。
INDEXEDDB_ABORTEDIndexedDB 交易被中止。
INDEXEDDB_BLOCKED開啟資料庫時被另一個分頁中的連線擋住。
INDEXEDDB_CONNECTION_CLOSING請求開始時資料庫連線正在關閉。
INDEXEDDB_OPEN_FAILED無法開啟資料庫。
INDEXEDDB_REQUEST_FAILEDIndexedDB 請求失敗。
INDEXEDDB_STORE_MISSING已建立的資料庫中沒有這個物件存放區。
INVALID_STORAGE_RECORD已儲存的紀錄不是有效的 restate 紀錄。
INVALID_STORED_VALUE值沒有通過 validate。
LIFECYCLE_LIMIT某個 updater 不斷地啟動又停止。
LOAD_FAILED紀錄無法載入,因此自動儲存或批次儲存沒有取代它。
MMKV_UNAVAILABLE無法載入 react-native-mmkv。
MULTIPLE_ERRORS一次操作中有多個回呼失敗;請查看 error.errors。
NOTIFICATION_LIMIT觀察者在迴圈中不斷安排新的變化。
OBSERVER_ERROR某個監聽器或生命週期回呼拋出了例外。
OPERATION_ABORTED某個儲存操作被取消。
QUEUE_FULL等待中的操作超過 maxPendingOperations 允許的數量。
REENTRANT_SETTER某個狀態 updater 在執行時試圖修改同一個 store。
SCOPE_DESTROYED使用已銷毀的 scope 建立 store。
SEQUENCE_EXHAUSTED內部序列的識別碼已用完。
STORAGE_BLOCKED逾時或中止後,先前的轉接器呼叫仍未結束。
STORAGE_TIMEOUT操作耗時超過 operationTimeoutMs。
STORAGE_UNAVAILABLE這裡無法使用儲存空間;store 會繼續在記憶體中運作。
STORAGE_VALUE_TOO_LARGE編碼後的值超過 maxStorageCharacters。
STORAGE_VERSION_MISMATCH紀錄的版本不同,而且沒有處理它的 migrate 函式。
STORE_DESTROYED訂閱了已銷毀的 store,或要求它使用儲存空間。

搜尋文件

搜尋所有指南的標題、說明與內文。