restate / v1.0.0
Confiabilidade desde o design
O que o restate garante quando o armazenamento é lento, falha ou não existe, e como ler os erros que ele informa.
Nesta página
As garantiasSalvamentos em ordemExperimenteQuando o carregamento falhaSalvar e fecharNenhum armazenamento disponívelValide e migre dados salvosUse seu próprio armazenamentoLimites e tempos de esperaCódigos de erroAs garantias
Esses comportamentos fazem parte do contrato da versão 1.0 e são cobertos pelos testes do pacote.
| Situação | O que o restate faz |
|---|---|
Vários salvamentos seguidos | Executa em ordem por store; um salvamento esperando na fila grava o valor mais recente. |
Um registro não carregou | O autoSave e os salvamentos em lote o ignoram com LOAD_FAILED; só um save() explícito o substitui. |
O componente é desmontado durante um salvamento | O salvamento pedido termina; gravações posteriores no store destruído são ignoradas. |
O armazenamento está indisponível | O store funciona em memória, status().available é false e os salvamentos são rejeitados. |
Um adaptador trava | A operação expira depois de operationTimeoutMs e o trabalho seguinte espera o adaptador terminar. |
Trabalho pendente demais | Novas operações são rejeitadas com QUEUE_FULL em vez de crescer sem limite. |
Salvamentos em ordem
As operações de um store nunca se sobrepõem. Um salvamento disparado enquanto outro espera pega o valor mais novo, então salvar a cada mudança grava o estado mais recente sem encher a fila.
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 writesExperimente
Deixe o armazenamento lento, faça as gravações falharem ou remova o armazenamento de vez.
Preparando o exemplo…
Quando o carregamento falha
restateManager.ready é rejeitado com BULK_OPERATION_FAILED e lista cada store que falhou. Até esse registro carregar, o autoSave e o saveAll não o substituem e informam LOAD_FAILED.
Tente de novo com initialize() para manter suas edições e salvá-las, chame restore() para descartá-las ou save() para sobrescrever o registro de propósito.
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);
}
}Salvar e fechar
Um salvamento pedido antes da desmontagem termina mesmo assim, então um handler de “Salvar e fechar” não precisa esperar.
function Document({ onClose }) {
const useDraft = useRestateScope((scope) => persistedRestate('', { scope, key: 'draft' }));
const saveAndClose = () => {
useDraft.save(); // finishes even after this component unmounts
onClose();
};
// …
}Valide e migre dados salvos
version, migrate e validate protegem você de registros antigos ou corrompidos. validate roda antes de salvar e depois de restaurar ou migrar.
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),
},
);Use seu próprio armazenamento
Qualquer objeto com getItem, setItem e removeItem serve. Os métodos podem retornar valores ou Promises; isAvailable é opcional.
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,
},
);Limites e tempos de espera
Ajuste quanto tempo uma operação pode durar, quantas podem esperar e qual o tamanho máximo de um valor.
persistedRestate(value, {
key: 'draft',
operationTimeoutMs: 10_000, // default 30000
maxPendingOperations: 64, // default 256
maxStorageCharacters: 1_000_000,
});Códigos de erro
Erros criados pelo restate têm name RestateError, um code e, nos stores salvos, key. Adaptadores de armazenamento e seus callbacks podem rejeitar com os próprios erros.
| Código | Significado |
|---|---|
BULK_OPERATION_FAILED | Uma chamada em lote como restateManager.ready ou saveAll teve falhas; veja error.failures. |
INDEXEDDB_ABORTED | Uma transação do IndexedDB foi abortada. |
INDEXEDDB_BLOCKED | A abertura do banco foi bloqueada por uma conexão em outra aba. |
INDEXEDDB_CONNECTION_CLOSING | A conexão com o banco estava fechando quando a requisição começou. |
INDEXEDDB_OPEN_FAILED | Não foi possível abrir o banco de dados. |
INDEXEDDB_REQUEST_FAILED | Uma requisição do IndexedDB falhou. |
INDEXEDDB_STORE_MISSING | O object store não existe em um banco já criado. |
INVALID_STORAGE_RECORD | Um registro salvo não é um registro válido do restate. |
INVALID_STORED_VALUE | Um valor não passou no validate. |
LIFECYCLE_LIMIT | Um updater ficou iniciando e parando sem parar. |
LOAD_FAILED | Um registro não pôde ser carregado, então um salvamento automático ou em lote não o substituiu. |
MMKV_UNAVAILABLE | Não foi possível carregar react-native-mmkv. |
MULTIPLE_ERRORS | Vários callbacks falharam em uma operação; veja error.errors. |
NOTIFICATION_LIMIT | Observadores continuaram agendando mudanças em loop. |
OBSERVER_ERROR | Um listener ou callback de ciclo de vida lançou um erro. |
OPERATION_ABORTED | Uma operação de armazenamento foi cancelada. |
QUEUE_FULL | Havia mais operações esperando do que maxPendingOperations permite. |
REENTRANT_SETTER | Um updater de estado tentou mudar o mesmo store enquanto rodava. |
SCOPE_DESTROYED | Um scope destruído foi usado para criar stores. |
SEQUENCE_EXHAUSTED | Uma sequência interna ficou sem identificadores. |
STORAGE_BLOCKED | Uma chamada anterior ao adaptador não terminou depois de um tempo esgotado ou cancelamento. |
STORAGE_TIMEOUT | Uma operação demorou mais que operationTimeoutMs. |
STORAGE_UNAVAILABLE | O armazenamento não pode ser usado aqui; o store continua funcionando em memória. |
STORAGE_VALUE_TOO_LARGE | O valor codificado é maior que maxStorageCharacters. |
STORAGE_VERSION_MISMATCH | Um registro tem outra versão e nenhuma função migrate trata dela. |
STORE_DESTROYED | Houve tentativa de assinar um store destruído ou de pedir que ele usasse o armazenamento. |