【Flutter入門】StatefulWidgetはなぜ2つに分かれているのかについて解説するよ。

StatefulWidgetが2つにわかれている理由

本記事は、マルチプラットフォーム開発のSDK【Flutter】を用いたモバイルアプリ開発入門の為の記事です。

ダーフク

Flutterアプリの開発で最初に目にする【StatefulWidget】。このStatefulWidgetは、クラスが2つに分かれています。本記事ではこの理由について解説していきます。

StatefulWidgetについて復習

はじめに、StatefulWidgetで特徴的な部分に関して復習をしておきます。

  1. 親Widgetから不変の値を受け取る場合、finalを宣言する
  2. コンストラクターで変数に値を設定
  3. Stateクラスをインスタンス化する
  4. Stateクラスで変数の値を更新する際、setStateを呼ぶ
  5. 画面に描画するWidgetを返すbuild関数を作成する
  6. 親Widgetで受け取った変数にアクセスする場合、widget.変数名を用いる

サンプルとして、以下にコードを上げておきます。

class MyHomePage extends StatefulWidget {
 // ➀親Widgetから受け取る変数の値が不変の場合、final変数として宣言する。
 // finalが宣言された変数はWidgetが作成される際(実行時)に値が適応され、それ以降値の変更は不可能となる。
  final String title;

 // ➁コンストラクター。クラス名({this.変数名})とすることで自動的に渡された親Widgetから渡された値を変数に設定する
  MyHomePage({Key key, this.title}) : super(key: key);

  // ➂ステートクラスをインスタンス化する。
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    // ➃変数の値を変更する際、setStateを必ず呼ぶ必要がある
    setState(() => _counter++);
  }

  // ➄描画するWidgetを返すbuild関数を定義する
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        // ➅StatefulWidgetから受け取った値をState側で使う場合、widget.変数名を用いる
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('$_counter'),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

StatefulWidgetの構成

上記のコードからも分かる通り、Stateful WidgetはStatefulWidgetを継承したMyHomePageと、Stateを継承した_MyHomePageStateの2種類から構成されています。

ここで、2つの疑問が浮かびます。

  1. なぜStatefulWidgetは2つに分かれているのか。
  2. StateがState<StatefulWidget名>を継承しているのはなぜか

➀なぜStatefulWidgetは2つに分かれているのか

StatefulWidgetは不変であるWidgetを継承しています。よって、StatefulWidget自体は不変である必要があります。

しかし、StatefulWidgetは可変である必要があるため、そこで登場するのがStateです。Stateに可変の要素を持たせています。

StatefulWidgetとStateの関係

Flutter SDKはStatefulWidgetを何度も再作成することができ、それに対しStateは1度だけ作成されます。

そして、再作成されたStatefulWidgetは既に作成されているStateを参照することで、Widgetの再作成(画面の描画)を効率的に行うことができます。

➁StateがState<StatefulWidget名>を継承しているのはなぜか

State側でStatefulWidgetで定義した変数にアクセスできるようにするためです。

 

StateクラスはStatefulWidgetが親Widgetから渡された変数にアクセスすることができます。

その時、上記の【StatefulWidgetの復習】で解説したようにwidget.変数名と表記します。

このような形でアクセスするためには、そのStateが参照しているStatefulWidgetの型は何かを定義することが必要です。

よって、State<StatefulWidget名>とすることでStatefulWidgetが持つ変数を、Stateが識別することができます。

StateがStatefulWidgetの型を定義する理由

最後に

本記事では、Flutterアプリの開発に際し多く使う機会があるStateful Widgetの構成について解説しました。

このように、Flutterではアプリのパフォーマンスが効率的に行われるように随所に配慮がされています。

そもそもStatefulWidgetとは何??という方は、以下の記事も参考にしていただければと思います。

StatelessWidgetとStatefulWidgetの違いとは 【Flutter入門】StatelessWidgetとStatefulWidgetの違い

参考

以下のStack overflowを参考にさせていただきました。

参考 Why are stateful widgets defined as two classes in flutter?stack overflow