Flutterとは?とStatefulWidgetの仕組み【初心者歓迎!Flutter入門所】

今最も熱いアプリ開発フレームワークであるFlutter。そんなFlutterをプログラミング初心者でもわかりやすく説明していきます。なるべく難しい言葉は使わず、Flutterの「雰囲気」を伝えられればな、と思います。初回はStatefulWidgetです。StatefulWidgetってFlutterを勉強していると最初に出てきますが…わかりにくいです。Flutterの基本とStatefulWidgetの仕組みを勉強してみましょう。

この記事はこんなヒトにオススメ
  • Flutterに興味があって環境構築してみたけど、どんな仕組みで動いてるんだろ?
  • StatefulWidgetについて、とりあえずどういう仕組みになっているかを知りたい
  • StateとStatefulWidgetの関係について、概要を知りたい
目次

Flutterってどんな仕組みで動いてる?

Flutterの細かいメリットや環境構築なんかはググればいくらでも出てくるので、その辺は他のブログなどにお任せします。

ここでは、実際に環境構築してみたけど、Flutterってどんな感じで開発していくんだろ?という人向けに説明していきたいと思います。

Flutterの基本は「Widget」です。ぶっちゃけると、全てWidgetでできています

スマホのアプリをイメージしてもらえればわかりやすいと思いますが、背景もWidget、ヘッダーもWidget、ボタンもWidget、リストもWiget、、、ぜーんぶWidgetでできています。

それが積み重なったり(親子Widget)、並んだり(兄弟Widget)してアプリを構成しています。

Flutterアプリの構成要素Widget

もちろん、Widgetを作るために必要な文字列、配列、数値や、計算、分岐、繰り返しなどのプログラミング要素が合わさってアプリを動かしていきます。

また、Flutterの元となるDart言語はオブジェクト指向と呼ばれるプログラミング言語です。

オブジェクト指向、というのはざっくり説明すると、「機能を定義したもの」(クラスという)を書いて、それに「必要な情報を渡して、実際に使えるモノを作る」(モノのことをインスタンスという)という流れでプログラミングされるものです。

よく「機能を定義したもの」を「設計図」と例えますが、ビミョーに設計図とは違う気がします。もう少し「機能の定義」に特化している感じです。「設計図」は同じものしかできないので…。

例えば

色」と「スーツ」という外見をもち、「必殺技」というスキルをもつ「特撮ヒーロー」クラス

という機能を定義した(クラスを作った)としましょう。

すると、次の図のように「色」「スーツ」「必殺技」を渡せば、ある程度の型にはハマっているけど、異なる外見とスキルの特撮ヒーローを作ることができます。

クラスの説明

こんな感じで、機能や変数を持ったクラスを定義しておき、実際にインスタンス化(モノ化)して全体のプログラムを構築していく方針のプログラミング言語をオブジェクト指向と言います。

クマ

実際には「オブジェクト指向とはなんぞや?」と説明するのは結構難しいですし、「PHPは後付けのオブジェクト指向だ!」などといった議論もあります…。まぁ、オブジェクト指向という言葉にあまりとらわれずに、クラスなどの考え方をしっかり理解した方がいいかもしれませんね

StatefulWidgetのコード例

上記の特徴を持ったFlutterですが、まず出てくるStatefulWidgetが結構わかりにくいです。

ひとまず、スマホアプリとして考えたとき、以下の特徴が必要であることを押さえてください。

・アプリなんだから、ただ用意したデータを画面に表示するだけじゃない。ユーザーからの入力等で表示される画面を変えたい。
・でも一旦画面には表示しちゃってるから、データを受け取ったら画面を再描画をする仕組みが必要。

そこで登場するのがStatefulWidgetです。StatefulWidgetの役割を簡単に説明すると、

ユーザーから受け取った入力を受けて画面を再描画する

という役割を担っています。

ここまで理解したところで、いつものデモアプリのコード(の一部)を載せておきます。

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

特にStatefulWidgetとStateの関係がわかりにくい印象です。

StatefulWidgetとStateの関係

StatefulWidgetとStateの関係
クマ

大体イメージにするとこんな感じかな?

1.StatefulWidgetが、createState()(という機能)でStateが持つ状態を描写します。StatefulWidgetとStateは対になって働いているところに注意してください。ですが、実際にStatefulWidgetがやってることはこのくらいです。

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}
クマ

MyHomePage({Key key, this.title}) : super(key: key);はコンストラクタと呼ばれるものです。先ほど説明した通り、クラスは設計図のようなものです。つまり、「これとこれで作って!よろしく!」と宣言して初めてモノができます(これをインスタンスといいます)。そこを宣言してる、と思ってください。

クマ

createState()の前にある_MyHomePageStateはクラス名を宣言してます。クラスを使ってインスタンスを作成する場合は「このクラスで作ってね」と宣言するのは、お作法のようなものですね。

2. 一方StateがStatefulWidgetのメインです。Stateはbuildメソッド(「機能」のようなもの)を持っており、これによりWidgetの塊であるWidgetツリー(Scaffold以下)を返しています。

肝になるのはsetStateの部分です。デモではフローティングアクションボタンから関数を呼び出し、setStateで自分の状態を変更したよ、という通知をしています。 この通知を受け取り、StatefulWidgetが画面を再描写する、という流れになります。(図の緑の矢印の流れ。)

クマ

StatefulWidgetとStateは1組になってて、Stateが色んな情報を持ってるんだな。で、setStateでState自身の状態が変わった、という通知をしてStatefulWidgetに画面を再描写してもらうんだな。

StatefulWidgetはあまり使わない

クマ

いきなり何衝撃的なこと言ってんだ!StatefulWidget使わなかったら、どうやって状態変化を画面に反映させるんだよ!

StatefulWidgetとStateはよくできた仕組みですが、実際には、以下のようなデメリットがあります。

  • 離れたWidget間での状態変更を通知しにくい。(StateとStatefulWidgetが対になって動いてるから)
  • パフォーマンスが下がることがある。(状況によるが、いちいち全てのWidgetを再描写する)
  • メンテナンスしにくい。(Widgetやロジックを全部Stateに詰め込んでる

そこで、現在はriverpodという状態管理パッケージを使うのが主流になっています。 このパッケージ、便利なのですがなかなか私自身も使いこなせておらず、また勉強して記事にしたいと思います。

クマ

せっかく勉強したのに…

まとめ

今回はStatefulWidgetの仕組みを簡単にまとめてみました。結局StatefulWidgetはあんまり使わないよという結論ですが、Flutterの状態管理の基本ですので、イメージだけでも掴めればと思います。riverpodによる状態管理はまた別の記事にまとめたいと思います。

あなたへオススメ!
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次