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

【Flutter】UI = f(state) 〜 三つのツリーと BuildContext について

0
Last updated at Posted at 2026-03-26

はじめに

Flutterの「ウィジェットツリー」と「BuildContext」の概念について、

これらの裏側の仕組みを理解してコードを書くために、備忘録として書き記したいと思います。

本記事では、Flutterの根幹である $UI = f(state)$ の公式を軸に、その裏側を解説します。


1. Flutterの基本原則: UI = f(state)

FlutterのUI構築は、数学的な関数として表現できます。

$$UI = f(state)$$

  • $state$: アプリが保持するデータ(変数、ログイン状態、APIからのレスポンスなど)
  • $f$: Widget build(BuildContext context)の部分
    データをどう見た目に変換するかの「ルール」
  • $UI$: 画面上のピクセル

宣言的UIでは、「状態が変われば、関数 $f$ が再実行され、UIが再構築される」というシンプルな流れで画面が更新されます。

Riverpodの役割

この公式において、Riverpodは 「$state$ を管理し、$f$ へ適切に届けるデリバリー役」 です。

ref.watch(provider) を使うことは、「この $f$ は、この $state$ に依存しています」と宣言することを意味します。


2. 実は「3つのツリー」が動いている

「Flutterはウィジェットツリーでできている」と言われますが、内部では効率化のために3つの異なるツリーが並行して動いています。

  1. Widget Tree

    • 不変(Immutable)な構成
    • 非常に軽量で、頻繁に作り直される
    • ウィジェットの設計図であり、設定値(プロパティ)を設定する
  2. Element Tree

    • WidgetとRenderObjectを繋ぐオブジェクト
    • ツリーの状態(State)を保持する
    • BuildContext の正体はこの Element
    • ウィジェットの実体
  3. Render Tree

    • 画面上のサイズ計算やレイアウト、描画を実際に担当する重いオブジェクト

なぜ再構築(Rebuild)しても速いのか?

$state$ が変わって $f$ が再実行されると、Widget Treeは新しく作り直されます。

しかし、Element Treeが新旧のWidgetを比較(Diffing)し、

「本当に変更があった部分」だけを Render Tree に伝えて描き直させる ため、高速な動作が維持されます。


3. BuildContext とは何か?

build メソッドで渡される context

その正体は、前述の通り Element そのものです。

「そのウィジェットがツリーのどこにいるか」という位置情報(住所) であり、

言わば、家系図上の自分の位置を示すようなものです。

主な役割:ツリーを遡って情報を探す

ウィジェットは単体では設計図であり、ツリーを構成するコンポーネントパーツ(部品)のですが、context というハンドルを使うことで、ツリーの上位にある情報を探しに行けます。

  • Theme.of(context):親のテーマ情報を取得。
  • Navigator.of(context):ルート管理(住所を辿って遷移を依頼)。
  • MediaQuery.of(context):画面サイズを取得。

4. 再構築(Rebuild)の最適化

$UI = f(state)$ を効率化するために、コーディングの際に意識するポイントをまとめます。

const コンストラクタを使う

const で宣言されたウィジェットは、親が再構築されても「内容が変わらないもの」と保証されるため、再計算が完全にスキップ されます。

最も手軽で強力な最適化です。

② Widgetの抽出(リファクタリング)

巨大な build メソッドは避けましょう。

小さなウィジェットに切り出すことで、再構築の範囲をそのウィジェット内に限定 できます。

③ Riverpodの select で監視を絞る

// 悪い例:User全体が変わるたびに再構築
final user = ref.watch(userProvider);

// 良い例:名前が変わった時だけ再構築
final name = ref.watch(userProvider.select((u) => u.name));

④ Async Gap への対策

​非同期処理(await)の後に context を使う際は、必ず mounted チェックを行いましょう。

await someFuture();
if (!context.mounted) return; // 親ウィジェットが既に破棄されていないか確認
Navigator.of(context).pop();

まとめ

  • ​Flutterは $UI = f(state)$ という関数である
  • Widgetは設計図。裏側のElementとRenderObjectが効率化を担っている
  • ​BuildContextは「ツリー内の住所」。上位の情報を引き出すために使う
  • 最適化の基本は「再構築の範囲をいかに絞るか」にある

参考

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