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();から始めてください。
チャレンジ
中級上部のバーにあるハートをタップすると、ヒントが変わります。これは、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();
},
),
),
),
);
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
データとネットワークのすべてのレッスン
自分で練習してみよう: Flutterオンラインコンパイラ