Pobierz raz w initState
Część sekcji Dane i sieć ścieżki Flutter w Coddy. Lekcja 7 z 27.
Flutter wywołuje build ponownie za każdym razem, gdy ekran jest odrysowywany: po każdym setState, gdy telefon się obraca, gdy zmienia się widget nadrzędny. Może się to zdarzać wiele razy na sekundę. build powinno tylko opisywać ekran, nigdy rozpoczynać żadnych działań.
Dlatego fetch umieszczone wewnątrz build uruchamia się ponownie przy każdym odrysowaniu. Każde uruchomienie to nowe żądanie do serwera, a ekran może nagle wyświetlić inną odpowiedź, choć nic jej nie zażądało:
// nowe żądanie przy każdym ponownym rysowaniu
FutureBuilder<String>(
future: fetch('/tip'),
...
)Utwórz obiekt future raz, gdy ekran się otworzy, w initState, i za każdym razem przekazuj tę samą wartość future do FutureBuilder:
late Future<String> _tip;
@override
void initState() {
super.initState();
_tip = fetch('/tip');
}initState uruchamia się raz, przed pierwszym build. Rozpocznij je od super.initState();, tak jak wymaga tego Flutter.
Wyzwanie
ŚredniDotknij serca na górnym pasku: podpowiedź się zmienia, ponieważ fetch jest w build. Załaduj podpowiedź tylko raz:
- dodaj
late Future<String> _tip;do stanu - ustaw ją w
initStateza pomocąfetch('/tip') - przekaż
_tipdoFutureBuilder
Spróbuj swoich sił
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();
},
),
),
),
);
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Dane i sieć
2Ekrany ładowania
Wskaźnik ładowaniaPoznaj FutureBuilderPobierz raz w initStateWczytaj dane ponownie przyciskiemPociągnij, aby odświeżyć3Gdy wywołania kończą się niepowodzeniem
Przechwytywanie błędów za pomocą tryZgłaszanie błęduSprzątanie za pomocą finallyStan błędu w FutureBuilderPrzycisk „Spróbuj ponownie”Poćwicz samodzielnie: Kompilator Flutter online