restate / v1.0.0
State ที่เป็นของคอมโพเนนต์
ให้แต่ละเอกสาร กล่องโต้ตอบ หรือคำขอมี store ของตัวเอง ที่สร้างพร้อมคอมโพเนนต์และถูกปล่อยหลัง unmount
ในหน้านี้
useRestateScopeกฎของ factoryค่าเริ่มต้นจาก propsการเรนเดอร์ฝั่งเซิร์ฟเวอร์รอข้อมูลที่บันทึกไว้ของเอกสารลองดูเจ้าของที่อยู่นอก ReactuseRestateScope
factory ประกาศ store แล้วคืนมันออกมา restate เก็บผลลัพธ์ไว้ระหว่างการเรนเดอร์และทำลาย scope หลังคอมโพเนนต์ unmount ไม่ต้องเขียนฟังก์ชันปิดหรือ effect สำหรับเก็บกวาด
องค์ประกอบ Document สองตัวมี state แยกกัน หากต้องการแชร์เอกสารให้ลูก ให้ส่ง hook ที่คืนมาผ่าน props หรือ context ของคุณเอง
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>
);
}กฎของ factory
React อาจเรียก factory มากกว่าหนึ่งครั้งและทิ้งผลลัพธ์ จึงควรให้มันทำงานแบบซิงโครนัสและบริสุทธิ์
- ประกาศ store ใน factory และเรียก hook ที่คืนมาที่ระดับบนสุดของคอมโพเนนต์
- props เริ่มต้นจะถูกอ่านครั้งเดียว เหมือนในตัวเริ่มค่าของ useState
- กำหนด key ให้คอมโพเนนต์เมื่อเอกสารอื่นต้องการ state ใหม่
- หากไม่มี factory useRestateScope() จะคืน scope ที่คงที่สำหรับ store ที่คุณสร้างภายหลังใน effect หรือตัวจัดการเหตุการณ์
ค่าเริ่มต้นจาก props
ใช้ props เป็นค่าเริ่มต้น และใช้ key ของ React เพื่อเริ่มใหม่กับเอกสารอื่น
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} />;การเรนเดอร์ฝั่งเซิร์ฟเวอร์
โหลดข้อมูลใน route ฝั่งเซิร์ฟเวอร์แล้วส่งเป็น prop ค่าเริ่มต้นจะเป็นสแนปช็อตจากเซิร์ฟเวอร์ด้วย ใน Next.js App Router hook นี้อยู่ใน Client Component ซึ่งก็ยังเรนเดอร์บนเซิร์ฟเวอร์
'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>;
}รอข้อมูลที่บันทึกไว้ของเอกสาร
store แบบบันทึกใน scope จะเริ่มกู้คืนเมื่อคอมโพเนนต์ commit ฝั่งไคลเอนต์ และไม่ได้เป็นส่วนหนึ่งของ restateManager.ready ส่วนกลาง ให้รอ manager.ready ของ scope เองภายในขอบเขตการโหลด
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} />;
}ลองดู
เปิดและปิดเอกสาร แล้วดูว่า state ของมันเริ่มใหม่อย่างไร
กำลังเตรียมตัวอย่าง…
เจ้าของที่อยู่นอก React
เมื่อ state เป็นของบริการหรือคำขอฝั่งเซิร์ฟเวอร์ ให้สร้าง scope เองแล้วเรียก destroy() ตอนจบ การทำลาย scope ไม่เคยลบระเบียนที่บันทึกไว้
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(),
};
}