restate / v1.0.0
Stav patřící komponentě
Dejte každému dokumentu, dialogu nebo požadavku vlastní story, které vzniknou s komponentou a po jejím odpojení se uvolní.
Na této stránce
useRestateScopePravidla factoryVýchozí hodnoty z propsRenderování na serveruČekání na uložená data dokumentuVyzkoušejteVlastníci mimo ReactuseRestateScope
Factory deklaruje story a vrátí je. restate drží výsledek mezi rendery a po odpojení komponenty scope zničí. Není potřeba psát žádnou zavírací funkci ani úklidový effect.
Dva prvky Document mají nezávislé stavy. Chcete-li dokument sdílet s potomky, předejte vrácené hooky přes props nebo vlastní kontext.
import { restate, useRestateScope } from '@kkwaenggwari/restate';
function Document() {
const { useDraft, useSelection } = useRestateScope((scope) => ({
useDraft: restate('', { scope }),
useSelection: restate(0, { scope }),
}));
const text = useDraft();
const selection = useSelection();
return (
<section>
<input value={text} onChange={(event) => useDraft.set(event.target.value)} />
<button onClick={() => useSelection.set((n) => n + 1)}>Selection: {selection}</button>
</section>
);
}Pravidla factory
React může factory zavolat vícekrát a výsledky zahodit, proto ji držte synchronní a čistou.
- Story deklarujte ve factory; vrácené hooky volejte na nejvyšší úrovni komponenty.
- Počáteční props se čtou jednou, jako v inicializátoru useState.
- Dejte komponentě key, když jiný dokument potřebuje čerstvý stav.
- Bez factory vrací useRestateScope() stabilní scope pro story, které vytvoříte později v effectech nebo obsluhách.
Výchozí hodnoty z props
Použijte props jako výchozí hodnoty a key Reactu, abyste začali znovu s jiným dokumentem.
function Editor({ document }) {
// The initial value is captured once, like a useState initializer.
const useTitle = useRestateScope((scope) => restate(document.title, { scope }));
const title = useTitle();
return <input value={title} onChange={(event) => useTitle.set(event.target.value)} />;
}
// A different document gets fresh state.
<Editor key={document.id} document={document} />;Renderování na serveru
Načtěte data v serverové routě a předejte je jako prop. Výchozí hodnota zároveň poskytne snímek ze serveru. V App Router Next.js patří tento hook do Client Component, která se přesto renderuje na serveru.
'use client';
import { restate, useRestateScope } from '@kkwaenggwari/restate';
export default function Profile({ user }) {
const useProfile = useRestateScope((scope) => restate(user, { scope }));
const profile = useProfile();
return <p>{profile.name}</p>;
}Čekání na uložená data dokumentu
Ukládané story ve scope začnou obnovovat po commitu komponenty na klientovi a nejsou součástí globálního restateManager.ready. Počkejte na vlastní manager.ready daného scope uvnitř hranice načítání.
import { useEffect, useState } from 'react';
import { persistedRestate, useRestateScope } from '@kkwaenggwari/restate';
function Document({ documentId }) {
const { manager, useDraft } = useRestateScope((scope) => ({
manager: scope.manager,
useDraft: persistedRestate('', { scope, namespace: 'documents', key: documentId }),
}));
const [state, setState] = useState('loading');
useEffect(() => {
let active = true;
manager.ready.then(
() => active && setState('ready'),
() => active && setState('error'),
);
return () => {
active = false;
};
}, [manager]);
if (state === 'error') return <p>Could not load this document.</p>;
if (state === 'loading') return <p>Loading document…</p>;
return <Editor useDraft={useDraft} />;
}Vyzkoušejte
Otevírejte a zavírejte dokumenty a sledujte, jak jejich stav začíná od nuly.
Příprava příkladu…
Vlastníci mimo React
Když stav patří službě nebo serverovému požadavku, vytvořte scope sami a na konci zavolejte destroy(). Zničení scope nikdy nesmaže uložené záznamy.
import { createRestateScope, persistedRestate } from '@kkwaenggwari/restate';
export function createDocument(documentId) {
const scope = createRestateScope();
const useDraft = persistedRestate('', {
scope,
namespace: 'documents',
key: documentId,
});
return {
useDraft,
manager: scope.manager,
save: () => scope.manager.saveAll(),
destroy: () => scope.destroy(),
};
}