restate / v1.0.0
State, der einer Komponente gehört
Gib jedem Dokument, Dialog oder Request eigene Stores, die mit der Komponente entstehen und nach ihrem Unmount freigegeben werden.
Auf dieser Seite
useRestateScopeRegeln für die FactoryAnfangswerte aus PropsServer-RenderingAuf die gespeicherten Daten eines Dokuments wartenAusprobierenBesitzer außerhalb von ReactuseRestateScope
Die Factory deklariert Stores und gibt sie zurück. restate behält das Ergebnis über Renders hinweg und zerstört den Scope nach dem Unmount der Komponente. Eine Schließfunktion oder einen Cleanup-Effect musst du nicht schreiben.
Zwei Document-Elemente haben unabhängigen State. Um ein Dokument mit seinen Kindern zu teilen, gib die zurückgegebenen Hooks über Props oder deinen eigenen Context weiter.
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>
);
}Regeln für die Factory
React kann die Factory mehrfach aufrufen und Ergebnisse verwerfen, also halte sie synchron und rein.
- Deklariere Stores in der Factory; ruf die zurückgegebenen Hooks auf oberster Ebene der Komponente auf.
- Anfangs-Props werden einmal übernommen, wie bei einem useState-Initialisierer.
- Gib der Komponente einen key, wenn ein anderes Dokument frischen State braucht.
- Ohne Factory gibt useRestateScope() einen stabilen Scope für Stores zurück, die du später in Effects oder Handlern erstellst.
Anfangswerte aus Props
Nutze Props als Anfangswerte und einen React-key, um für ein anderes Dokument neu zu beginnen.
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} />;Server-Rendering
Lade die Daten in deiner Server-Route und gib sie als Prop weiter. Der Anfangswert liefert auch den Server-Snapshot. Im Next.js App Router gehört dieser Hook in eine Client Component, die trotzdem auf dem Server gerendert wird.
'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>;
}Auf die gespeicherten Daten eines Dokuments warten
Gespeicherte Stores in einem Scope beginnen mit der Wiederherstellung, nachdem die Komponente auf dem Client committet wurde, und gehören nicht zum globalen restateManager.ready. Warte in einer Lade-Boundary auf das eigene manager.ready des Scopes.
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} />;
}Ausprobieren
Öffne und schließe Dokumente und sieh zu, wie ihr State frisch beginnt.
Beispiel wird vorbereitet…
Besitzer außerhalb von React
Wenn ein Service oder ein Server-Request den State besitzt, erstellst du den Scope selbst und rufst am Ende destroy() auf. Das Zerstören eines Scopes löscht nie gespeicherte Datensätze.
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(),
};
}