📑

採用している状態管理パターンを言語化する

2025/02/16に公開

私は2017年ごろからReactをメインに開発しています。そしていろいろな状態管理のパターンを経験してきましたが、最近あるパターンに落ち着いてきたように思います。

この記事では、まず私が採用している状態管理パターンについて書きます。
それからなぜそのパターンに落ち着いたのかを説明したいと思います。

React.useStateを第一に検討する

状態管理については次のように考えています。

  • 状態管理を避けられないか
  • 基本はReact.useState
  • Jotaiは最小限に

状態管理を避けられないか、については過去に記事を書いています。

https://zenn.dev/michiharu/articles/f4922d5631393d

管理している状態を1つでも減らして、開発スピードを維持していきましょう。

まず、この発想がスタートラインです。まず状態管理が必要かどうかをしっかり検討します。

そして基本的に状態管理にはReact.useStateを使っています。
1つのコンポーネントに閉じている状態を扱うならReact.useStateを使うことに決めています。

複数コンポーネントから状態を扱う必要がある場合はJotaiを使うことにしていますが、そういうコードを読むコストは高いです(1つのコンポーネントに閉じている状態を扱うコードに比べて)。そのため、できるだけ複数コンポーネントから状態を扱う設計を避けるようにしています。

Redux Toolkitライクにコードを管理する

ここまでに説明では採用している状態管理のパターンにRedux Toolkitは登場しません。
しかし過去に採用していたRedux ToolkitのcreateSlicereducersをまとめて記述する方法は、とても可読性の高い優秀な方法だったと思っています。

そのためReact.useStateを使う場合、次のようなカスタムフックで状態を操作する関数をまとめて記述しています。

const useCounter = () => {
  const [state, setState] = React.useState(0);
  return React.useMemo(
    () => ({
      state,
      increment: () => setState(c => c + 1),
      decrement: () => setState(c => c - 1),
    }),
    [state],
  );
};

export default function FooComponent() {
  const counter = useCounter();
  ...
}

setStateはカスタムフックの外ではアクセスできないので、用意した関数以外の方法で状態が更新されることはないことがすぐに分かります。カスタムフックはReactコンポーネントと同じファイルに記述します。

Jotaiについても同様の考え方でコードを扱います。atomの定義にはexportを付けずに、具体的なケースごとの状態操作を実装したフックだけをexportします。

私は状態を操作する関数がまとまっているコードの様子を、Redux Toolkitへのリスペクトを込めて「Redux Toolkitライク」と呼んでいます。それはつまり状態管理のカプセル化です。

以上が現在採用している状態管理のパターンです。

なぜこのパターンなのか

なぜこのパターンに落ち着いているのかきちんと言語化せずにいましたが、以下の記事に言語化のヒントがありました。

https://zenn.dev/akfm/articles/react-team-vision

コンポーネントが自立して機能するよう設計することは、スケーラビリティーを生みます。
上述したReact.useStateの使い方は状態の扱いが1つのコンポーネントに閉じており、自立しているとみなすことができます。

ある状態を複数コンポーネントから扱っているということは、それらのコンポーネントは自立していません。ある状態と、関係する複数のコンポーネントを1つのコンポーネント群として扱うことで自立しているとみなすことができますが、コードリーティングの負担は大きくなります。つまり状態のロジックが、関係するコンポーネントをくっ付ける接着剤のように働いてしまうということです。

Jotaiは、Reduxとは異なり状態を分散管理することができるため採用しています。しかしそれでも複数コンポーネントにimportすれば、それらをコンポーネント群として扱う必要があるため、できるだけそういった設計を避けています。

まとめ

分散を意識して設計することが大規模アプリのスケーラビリティーにおいて重要!以上。

Discussion