restate / v1.0.0

State ที่เป็นของคอมโพเนนต์

ให้แต่ละเอกสาร กล่องโต้ตอบ หรือคำขอมี store ของตัวเอง ที่สร้างพร้อมคอมโพเนนต์และถูกปล่อยหลัง unmount

ในหน้านี้useRestateScopeกฎของ factoryค่าเริ่มต้นจาก propsการเรนเดอร์ฝั่งเซิร์ฟเวอร์รอข้อมูลที่บันทึกไว้ของเอกสารลองดูเจ้าของที่อยู่นอก React

useRestateScope

factory ประกาศ store แล้วคืนมันออกมา restate เก็บผลลัพธ์ไว้ระหว่างการเรนเดอร์และทำลาย scope หลังคอมโพเนนต์ unmount ไม่ต้องเขียนฟังก์ชันปิดหรือ effect สำหรับเก็บกวาด

องค์ประกอบ Document สองตัวมี state แยกกัน หากต้องการแชร์เอกสารให้ลูก ให้ส่ง hook ที่คืนมาผ่าน props หรือ context ของคุณเอง

JavaScript / JSX
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 เพื่อเริ่มใหม่กับเอกสารอื่น

JavaScript / JSX
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 ซึ่งก็ยังเรนเดอร์บนเซิร์ฟเวอร์

JavaScript / JSX
'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 เองภายในขอบเขตการโหลด

JavaScript / JSX
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 ไม่เคยลบระเบียนที่บันทึกไว้

JavaScript / JSX
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(),
  };
}

ค้นหาเอกสาร

ค้นหาในชื่อเรื่อง คำอธิบาย และเนื้อหาของคู่มือทั้งหมด