ilokesto

React 연동

React component가 @ilokesto/store 기반 상태를 구독해야 할 때 React adapter를 사용하세요. root package가 아니라 @ilokesto/state/react에서 import합니다.

Adapter type

UseState와 UseReducer는 plain-state와 reducer create() overload가 반환하는 hook을 나타냅니다. public API가 이 hook type을 받을 때 같은 React subpath에서 import하세요.

import type { UseReducer, UseState } from '@ilokesto/state/react';

Plain state hook

plain state는 작은 React state hook처럼 [selection, setState]를 반환합니다.

import { create } from '@ilokesto/state/react';

type CounterState = { count: number; label: string };

const useCounter = create<CounterState>({ count: 0, label: 'Clicks' });

export function CounterButton() {
  const [count, setCounter] = useCounter((state) => state.count);
  const [label] = useCounter((state) => state.label);

  return (
    <button onClick={() => setCounter((prev) => ({ ...prev, count: prev.count + 1 }))}>
      {label}: {count}
    </button>
  );
}

selector는 tuple 첫 번째 값으로 받을 값을 결정합니다. writer는 여전히 전체 state를 업데이트하므로 object update는 immutable하게 작성하세요.

Reducer hook

reducer state는 같은 create(reduce, initialState) overload를 사용합니다. tuple writer는 dispatch가 됩니다.

import { create } from '@ilokesto/state/react';

type Action = { type: 'increment' } | { type: 'reset' };

const reduce = (state: { count: number }, action: Action) => {
  if (action.type === 'increment') return { count: state.count + 1 };
  if (action.type === 'reset') return { count: 0 };
  return state;
};

const useCounter = create(reduce, { count: 0 });

function ReducerCounter() {
  const [count, dispatch] = useCounter((state) => state.count);
  return <button onClick={() => dispatch({ type: 'increment' })}>{count}</button>;
}

React 생명주기 밖에서 사용하기

readOnly()와 writeOnly()는 hook function에 붙어 있습니다. hook을 호출하면 안 되는 module, service callback, test, event bus에서 사용하세요.

const readCount = useCounter.readOnly((state) => state.count);
const dispatch = useCounter.writeOnly();
dispatch({ type: 'reset' });

주의할 점

  • 반환된 function은 내부적으로 useSyncExternalStore를 쓰는 React hook입니다. component 또는 custom hook 안에서만 호출하세요.
  • getServerSnapshot은 store initial state에서 시작하므로 SSR hydration에서는 server/client 초기 상태를 맞추세요.
  • selector는 pure하고 cheap하게 유지하세요. React가 snapshot을 memoize해도 비싼 selector는 render/snapshot 작업 중 실행됩니다.

목차