restate / v1.0.0

컴포넌트가 소유하는 상태

문서, 대화상자, 요청마다 컴포넌트와 함께 만들어지고 언마운트 뒤 해제되는 자기 스토어를 줍니다.

이 페이지에서useRestateScopefactory 규칙props로 초기값 주기서버 렌더링문서의 저장 데이터 기다리기직접 해 보기React 밖의 소유자

useRestateScope

factory가 스토어를 선언해 반환합니다. restate는 그 결과를 렌더 사이에 유지하고, 컴포넌트가 언마운트되면 scope를 파괴합니다. 따로 작성할 close 함수나 정리 effect가 없습니다.

두 Document는 서로 독립된 상태를 가집니다. 자식과 공유하려면 반환된 훅을 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를 여러 번 호출하고 결과를 버릴 수 있으므로 동기적이고 순수하게 유지하세요.

  • 스토어는 factory에서 선언하고, 반환된 훅은 컴포넌트 최상위에서 호출합니다.
  • 초기 props는 useState 초기값처럼 한 번만 반영됩니다.
  • 다른 문서에 새 상태가 필요하면 컴포넌트에 key를 주세요.
  • factory 없이 useRestateScope()를 부르면 effect나 핸들러에서 나중에 만들 스토어를 위한 안정된 scope를 반환합니다.

props로 초기값 주기

props를 초기값으로 쓰고, 다른 문서로 새로 시작할 때는 React key를 쓰세요.

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} />;

서버 렌더링

서버 라우트에서 데이터를 불러와 prop으로 넘기세요. 초기값이 서버 스냅샷도 됩니다. Next.js App Router에서는 이 훅을 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>;
}

문서의 저장 데이터 기다리기

scope 안의 저장 스토어는 클라이언트에서 컴포넌트가 커밋된 뒤 복원을 시작하고, 전역 restateManager.ready에는 포함되지 않습니다. 로딩 경계에서 해당 scope의 manager.ready를 기다리세요.

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} />;
}

직접 해 보기

문서를 열고 닫으며 상태가 새로 시작되는지 확인하세요.

예제를 준비하는 중…

React 밖의 소유자

서비스나 서버 요청이 상태를 소유한다면 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(),
  };
}

문서 검색

모든 가이드의 제목·설명·본문을 검색합니다.