5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React 19.2の<Activity>をFintanのTodoアプリで試してみた

5
Last updated at Posted at 2025-12-20

はじめに

React 19.2で追加された<Activity>の理解を深めるために、FintanのSPA + REST API構成のハンズオンのTodoアプリをローカルにダウンロードし、<Activity>を組み込んでみました。

なお、ハンズオンアプリの環境構築やバージョンアップ作業に関することは記載しません。

Activityとは?

React 19.2で追加された新機能です。公式ドキュメントによると:
https://react.dev/reference/react/Activity

Activity バウンダリを用いてコンポーネントを非表示にすると、React は state を後で使うために「セーブ」しておくことができます。

通常、{isOpen && <Component />}みたいに条件分岐するとコンポーネントがアンマウントされてstateも消えます。
でも<Activity>を使えば、非表示にしてもstateを保持できます。

どう動くのか?

  • mode="hidden"の時

    • display: noneで見えなくなる
    • useEffectのクリーンアップ関数が実行される(タイマーやAPI接続などを停止)
    • でもstateは残ってる
    • 新しいpropsに反応して再レンダーはされるが、優先度が低くなる
  • mode="visible"に戻した時

    • 以前のstateが復元される
    • useEffectが再実行される(タイマーやAPI接続などを再開)

追加した機能について

<Activity>の機能は「非表示にしてもstateを保持する」こと。
公式ドキュメントだとサイドバーの開閉が例として出てます。

今回は学習目的で、TodoアプリにTodoの編集パネルを追加してみました。
具体的には、Todoをクリックすると右側にパネルが開いて、そこでTodoの内容を編集できる機能です。

やりたいこと:

  • Todoクリックで右側にパネルを表示
  • パネル内でTodoの内容を編集
  • 保存せずに閉じても編集中の内容を保持

画面はこんな感じで作りました。

image.png

Activity使う前の実装

まず、右側にパネルを表示する部分まで実装してみます。

TodoBoard.tsx

export const TodoBoard: React.FC = () => {
  const [selectedTodoId, setSelectedTodoId] = useState<number | null>(null);
  const selectedTodo = todos.find(todo => todo.id === selectedTodoId);

  return (
    <div>
      <TodoList onTodoClick={(id) => setSelectedTodoId(id)} />
      
      {selectedTodo && (
        <TodoDetailPanel
          todo={selectedTodo}
          onClose={() => setSelectedTodoId(null)}
          onSave={handleDetailSave}
        />
      )}
    </div>
  );
};

TodoDetailPanel.tsx

export const TodoDetailPanel: React.FC<Props> = ({ todo, onClose, onSave }) => {
  const [editText, setEditText] = useState(todo.text);

  const handleSave = () => {
    onSave(todo.id, editText);
  };

  return (
    <div className={styles.panel}>
      <div className={styles.header}>
        <h2>Todo詳細</h2>
        <button onClick={onClose}></button>
      </div>
      <textarea
        value={editText}
        onChange={(e) => setEditText(e.target.value)}
      />
      <button onClick={handleSave}>保存</button>
    </div>
  );
};

何が問題?

この実装だと:

  1. サイドパネルでテキスト編集中
  2. 保存せずに✕で閉じる → selectedTodonullになってコンポーネントがアンマウント
  3. 同じTodoをもう一度開く → コンポーネントが新規マウント
  4. 編集してた内容が消えています

{selectedTodo && ...}の条件分岐でコンポーネントが完全に消えるので、editTextのstateも一緒に消えます。

Activity使ってみる

では<Activity>で状態を保持できるようにしてみます。

最初の実装

1つの<Activity>で全部管理してみます。

<Activity mode={selectedTodoId !== null ? "visible" : "hidden"}>
  {selectedTodo && (
    <TodoDetailPanel todo={selectedTodo} ... />
  )}
</Activity>

あるTodoを編集して、保存せずに閉じて、再度編集パネルを開くと状態はリセットされずに表示されました。

しかし、Todo1を編集してからTodo2を開くと、Todo1の編集内容がTodo2にも表示されます

1つのTodoDetailPanelを使い回してるので、editTextのstateもTodo間で共有されちゃいます。

今回は複数のTodoを編集した際に、それぞれの状態を保持するようにしてみます。

Todo毎にActivityを作る

Todo毎にActivityを作ることにします。

この方法だとTodo分のコンポーネントが常にマウントされるため、パフォーマンスへの懸念があります。

他の実装案もありますが、今回は気にせず実装します。

TodoBoard.tsx(Activity使った後)

export const TodoBoard: React.FC = () => {
  const [selectedTodoId, setSelectedTodoId] = useState<number | null>(null);

  return (
    <div>
      <TodoList onTodoClick={(id) => setSelectedTodoId(id)} />
      
      {todos.map(todo => (
        <Activity 
          key={todo.id}
          mode={selectedTodoId === todo.id ? "visible" : "hidden"}
        >
          <TodoDetailPanel
            todo={todo}
            onClose={() => setSelectedTodoId(null)}
            onSave={handleDetailSave}
          />
        </Activity>
      ))}
    </div>
  );
};

これでどう変わった?

ちゃんと動くようになりました:

  1. Todo1を編集中に閉じる → Todo1の<Activity>mode="hidden"になってeditTextが保持される
  2. Todo2を開く → Todo2の<Activity>mode="visible"になる(Todo1とは別)
  3. Todo1をもう一度開くmode="visible"に戻って編集途中の内容が復元される

各Todoが独立してるので、複数のTodoを編集中でもそれぞれの内容が個別に保持されます。

まとめ

React 19.2の<Activity>を実際に使ってみました。

使う前と使った後で動作がどう変わるか、ざっくり確認できました。

参考

5
0
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
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?