【Flutter】StatelessWidgetとStatefulWidget

Table of Contents

こんにちは。実家から送られてきた大量の野菜をどうやって消費しようか悩んでいる中村です。
今回はFlutterで避けては通れないStatelessWidgetとStatefulWidgetについて書いていこうと思います!

StatelessWidgetとStatefulWidgetの違い

Stateful and stateless widgetという公式ドキュメントは英語ですが機械翻訳にかけながらなんとか読み解いていきます。

A stateless widget never changes. Icon, IconButton, and Text are examples of stateless widgets. Stateless widgets subclass StatelessWidget.
A stateful widget is dynamic: for example, it can change its appearance in response to events triggered by user interactions or when it receives data. Checkbox, Radio, Slider, InkWell, Form, and TextField are examples of stateful widgets. Stateful widgets subclass StatefulWidget.

つまり動きがない(Stateless)か、動きがあるか(Stateful)で判断すれば良いということです。flutterへの理解が進むと、再ビルドのタイミングなどが違うという差が分かってきますが初学者はこの理解でとりあえずは問題ないと思います

StatelessWidgetの例

Flutterの初期プロジェクトを利用して説明していきます。

				
					class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
				
			

この部分がStatelessWidgetです。
中を見てみるとMaterialAppのtitleや、子Widgetにデータを渡してアプリの統一感を出すことができるthemeなどが入っています。
これらは変更の必要がないものですのでStatelessWidgetで問題ありません。
逆に動きのあるhomeはStatefulWidgetで実装したいのでMyHomePageとして切り分けています。

StatefulWidgetの例

				
					class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State createState() => _MyHomePageState();
}

class _MyHomePageState extends State {
  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: [
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

				
			

初期プロジェクトのこの部分がStatefulWidgetです。
中を見ていくと

				
					 floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
				
			

のようにボタンがあり、このボタンは押されたときに_incrementCounterという関数を呼び出します。
_incrementCounterを見ていきます。

				
					  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
				
			

この関数で_counterの数を増やし、ボタンを押した数を保管しています。
この更新を担っているのがsetStateというメソッドです。
setStateは_counterの値が変わったことをStatefulWidgetに伝える役割をしています。
これにより再ビルドされて画面が再描画されるという訳です。

ちなみに動きのないWidgetを普通にStatefulWidgetでも使っていますが、これは問題ありません。
例えば下記のようにカウンターアプリをすべてStatefulWidgetで書き換えることもできます。

				
					import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp(title: 'Flutter Demo Home Page'));
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State createState() => _MyAppState();
}

class _MyAppState extends State {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                const Text(
                  'You have pushed the button this many times:',
                ),
                Text(
                  '$_counter',
                  style: Theme.of(context).textTheme.headline4,
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: const Icon(Icons.add),
          ),
        ));
  }
}

				
			

ならStatelessWidgetいらないじゃんって話になりますが、自分はビルドの回数やビルドする場所を減らすためにStatelessWidgetがあるのだと思います。(勝手に思っているだけなので本当は違うかもしれません。)

終わりに

今回はStatelessWidgetとStatefulWidgetについて解説しました。
自分でもまだ勉強中のところですので拙い説明になってしまいましたが参考になれば幸いです。
それではまた!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール