LoginSignup
1
1

外部データを購読するuseSyncExternalStore

Posted at

useSyncExternalStore

useSyncExternalStoreはReactが提供するブラウザAPIなどの外部の状態ストアと同期するためのhooksです。
型情報はシンプルで以下のようになっています。

export function useSyncExternalStore<Snapshot>(
    subscribe: (onStoreChange: () => void) => () => void,
    getSnapshot: () => Snapshot,
    getServerSnapshot?: () => Snapshot,
): Snapshot;

subscribeが外部の状態ストアを購読する関数、getSnapshotが現在の外部の状態ストアから値を取得する関数、getServerSnapshotはサーバー上で実行された時に初期値を返すような関数です。
subscribeに渡す関数がレンダリング間で異なっている場合は、再購読することになるのでコンポーネント外で宣言するか、useCallbackで宣言するようにしてください。
subscribeが引数に持つonStoreChangeが呼び出されると、Reactは対象のコンポーネントを再レンダリングします。

例: 状態ストアを自作する

値がアプリケーション全体で共有され、その変化によって利用するコンポーネントが再レンダリングされるような仕組みをuseSyncExternalStoreを作成します。
簡単な条件としてカウンターを考えていきます。まずは、値を定義します。アプリケーション全体で利用するために、グローバルに定義します。

let count = 0;
const getSnapshot = () => {
  return count;
};

export default function App() {
...

SnapShotとしてコンポーネントから読み取るための関数も定義しています。
そして、countに対する変更を定義します。今回は+1だけするincrementを定義します。

const increment = () => {
  count++;
};

このままではcountの更新が伝わらないため、subscribeを定義してReactに更新を伝えられるように準備します。

let listeners: (() => void)[] = [];

const increment = () => {
  count++;
  emitChange();
};

const subscribe = (listener: () => void) => {
  listeners = [...listeners, listener];
  return () => {
    listeners = listeners.filter((l) => l !== listener);
  };
};

function emitChange() {
  for (let listener of listeners) {
    listener();
  }
}

listeners変数を定義して、subscribeが呼び出された時に、引数のonStoreChangeを詰め込むようにしました。さらに、listenersが全て実行されるemitChangeを定義して、countが更新される(今回だとincrementが呼ばれる)度にlistenerを発火して変更毎にレンダリングを起こして画面へ反映を試みるようにします。

それらを用いてuseSyncExternalStoreを使えばアプリケーション全体で値が共通され、値の更新ごとにレンダリングが走るようになります。

export default function App() {
  const snapshot = useSyncExternalStore(subscribe, getSnapshot);

  return <button onClick={increment}>{snapshot}</button>;
}

今回の仕組みに限らず、基本的にはuseSyncExternalStoreではなく、useStateuseReduceruseContextやその他状態管理ライブラリなどを利用して記述するようにしましょう。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1