Menu
CoddyTech

initStateで一度だけデータを取得

CoddyのFlutterジャーニー「データとネットワーク」セクションの一部。レッスン 7/27。

Flutterは画面が再描画されるたびにbuildを再度呼び出します。各setStateの後、スマートフォンの向きが変わったとき、親が変更されたときなどです。1秒間に何度も呼び出されることもあります。buildは画面を記述するだけにし、処理を開始してはいけません。

そのため、buildの中に書かれたfetchは、再描画のたびに再び実行されます。実行するたびにサーバーへの新しいリクエストが送信され、誰も求めていないのに画面に別の結果が表示されることがあります。

// 再描画のたびに新しいリクエスト
FutureBuilder<String>(
  future: fetch('/tip'),
  ...
)

画面が開いたときにinitStateでfutureを一度だけ作成し、毎回同じfutureをFutureBuilderに渡します。

late Future<String> _tip;

@override
void initState() {
  super.initState();
  _tip = fetch('/tip');
}

initStateは、最初のbuildの前に一度だけ実行されます。Flutterの指示どおり、super.initState();から始めてください。

challenge icon

チャレンジ

中級

上部のバーにあるハートをタップすると、ヒントが変わります。これは、fetchがbuild内にあるためです。ヒントを一度だけ読み込みましょう。

  • 状態にlate Future<String> _tip;を追加する
  • initStateでfetch('/tip')を使って設定する
  • FutureBuilderに_tipを渡す

自分で試してみよう

import 'package:flutter/material.dart';

import 'api.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: TipScreen(),
    );
  }
}

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

  @override
  State<TipScreen> createState() => _TipScreenState();
}

class _TipScreenState extends State<TipScreen> {
  bool liked = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Tip of the Day'),
        actions: [
          IconButton(
            icon: Icon(liked ? Icons.favorite : Icons.favorite_border),
            onPressed: () {
              setState(() {
                liked = !liked;
              });
            },
          ),
        ],
      ),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: FutureBuilder<String>(
              future: fetch('/tip'),
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  return Text(
                    snapshot.data!,
                    textAlign: TextAlign.center,
                    style: const TextStyle(fontSize: 24),
                  );
                }
                return const CircularProgressIndicator();
              },
            ),
        ),
      ),
    );
  }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

データとネットワークのすべてのレッスン

自分で練習してみよう: Flutterオンラインコンパイラ