Kodokon kodokon.com

状態の共有:状態のリフトアップとコールバック

状態を共通の祖先に置き、子ウィジェットを、コールバックを通じて変化を報告する制御されたウィジェットに変えましょう。

8 分 · 3 問

このレッスンを Kodokon で開く

よくある状況です。数量セレクターと、別の場所に表示される合計が、同じデータを共有する必要があります。黄金律はこうです。状態はそれに依存するウィジェットの最も近い共通の祖先に置かれます。親がデータを所有し、それをパラメーターとして下へ渡し、上へと流れ戻るコールバックを通じて変化を受け取ります。これが"状態のリフトアップ"です。

DART
import 'package:flutter/material.dart';

class CartScreen extends StatefulWidget {
  const CartScreen({super.key});

  @override
  State<CartScreen> createState() => _CartScreenState();
}

class _CartScreenState extends State<CartScreen> {
  int _quantity = 1;

  void _updateQuantity(int value) {
    setState(() => _quantity = value);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Cart')),
      body: Column(
        children: [
          QuantitySelector(
            quantity: _quantity,
            onChanged: _updateQuantity,
          ),
          Text('Total: ${_quantity * 20} €'),
        ],
      ),
    );
  }
}
親が状態を所有し、値とコールバックを渡す

子は制御されたウィジェットになります。StatelessWidgetであり、何も保持せず、受け取った値を表示し、onChangedを通じてそれぞれの意図を知らせます。ValueChanged<int>は単にvoid Function(int)のエイリアスです。数量が1のときにマイナスボタンが無効になっていることに注目してください。onPressednullを渡すだけで十分であり、このロジックは受け取った値から直接導かれます。

DART
import 'package:flutter/material.dart';

class QuantitySelector extends StatelessWidget {
  const QuantitySelector({
    super.key,
    required this.quantity,
    required this.onChanged,
  });

  final int quantity;
  final ValueChanged<int> onChanged;

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        IconButton(
          icon: const Icon(Icons.remove),
          onPressed: quantity > 1
              ? () => onChanged(quantity - 1)
              : null,
        ),
        Text('$quantity'),
        IconButton(
          icon: const Icon(Icons.add),
          onPressed: () => onChanged(quantity + 1),
        ),
      ],
    );
  }
}
子は受け取った値を表示し、意図を上へ報告する

あなたは気づかないうちにこの契約をいつも使っています。CheckboxSliderSwitchはすべて制御されたウィジェット(value + onChanged)です。ツリーが深くなり、コールバックを五段階も通し続けるのが面倒になったら、状態管理の解決策を知る時が来ます。それが次のモジュールのテーマです。

理解度チェック

このレッスンの要点をしっかり覚えているか確認しましょう。

  1. 二つの兄弟ウィジェットが共有する状態はどこに置くべきですか?
    • 二つのウィジェットそれぞれの中に
    • 最も近い共通の祖先の中に
    • グローバル変数の中に
    • MaterialAppの中に
  2. 子ウィジェットはどうやって状態の変更を要求しますか?
    • 親に対して直接setStateを呼ぶ
    • パラメーターとして受け取ったプロパティを変更する
    • 親から提供されたコールバックを呼び出す
  3. 制御されたウィジェットとは何ですか?
    • 自身の状態を持たず、値を受け取り、コールバックを通じて変化を報告するウィジェット
    • setStateを使わなければならないウィジェット
    • 単体テストで覆われたウィジェット
    • constで宣言されたウィジェット