restate / v1.0.0
State milik komponen
Beri setiap dokumen, dialog, atau permintaan store sendiri yang dibuat bersama komponen dan dilepas setelah ia unmount.
Di halaman ini
useRestateScopeAturan factoryNilai awal dari propsServer renderingMenunggu data tersimpan dokumenCobaPemilik di luar ReactuseRestateScope
Factory mendeklarasikan store dan mengembalikannya. restate menyimpan hasilnya antar render dan menghancurkan scope setelah komponen unmount. Tidak perlu menulis fungsi penutup atau effect pembersihan.
Dua elemen Document punya state terpisah. Untuk membagikan dokumen ke anak-anaknya, teruskan hook yang dikembalikan lewat props atau context Anda sendiri.
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>
);
}Aturan factory
React dapat memanggil factory lebih dari sekali dan membuang hasilnya, jadi jaga agar sinkron dan murni.
- Deklarasikan store di dalam factory; panggil hook yang dikembalikan di tingkat teratas komponen.
- Props awal dibaca sekali, seperti pada inisialisasi useState.
- Beri komponen key saat dokumen lain membutuhkan state yang baru.
- Tanpa factory, useRestateScope() mengembalikan scope stabil untuk store yang Anda buat nanti di effect atau handler.
Nilai awal dari props
Gunakan props sebagai nilai awal, dan key React untuk memulai ulang dengan dokumen lain.
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
Muat data di route server dan teruskan sebagai prop. Nilai awal sekaligus menjadi snapshot server. Di Next.js App Router, hook ini berada di Client Component, yang tetap dirender di server.
'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>;
}Menunggu data tersimpan dokumen
Store tersimpan dalam scope mulai memulihkan saat komponen di-commit di klien dan bukan bagian dari restateManager.ready global. Tunggu manager.ready milik scope itu sendiri di dalam batas pemuatan.
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} />;
}Coba
Buka dan tutup dokumen, lalu lihat bagaimana state-nya dimulai ulang.
Menyiapkan contoh…
Pemilik di luar React
Saat state dimiliki sebuah service atau permintaan server, buat scope sendiri dan panggil destroy() di akhir. Menghancurkan scope tidak pernah menghapus catatan tersimpan.
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(),
};
}