Cargar una vez en initState
Parte de la sección Datos y red del Journey de Flutter de Coddy. Lección 7 de 27.
Flutter vuelve a llamar a build cada vez que se vuelve a dibujar la pantalla: después de cada setState, cuando gira el teléfono, cuando cambia un elemento principal. Esto puede ocurrir muchas veces por segundo. build solo debe describir la pantalla, nunca iniciar tareas.
Por eso, un fetch escrito dentro de build se ejecuta de nuevo en cada redibujado. Cada ejecución es una nueva solicitud al servidor, y la pantalla puede mostrar una respuesta distinta cuando nadie la ha pedido:
// una nueva solicitud en cada redibujado
FutureBuilder<String>(
future: fetch('/tip'),
...
)Crea el futuro una sola vez, cuando se abre la pantalla, en initState, y dale a FutureBuilder ese mismo futuro cada vez:
late Future<String> _tip;
@override
void initState() {
super.initState();
_tip = fetch('/tip');
}initState se ejecuta una vez, antes del primer build. Inícialo con super.initState();, tal como lo pide Flutter.
Desafío
IntermedioToca el corazón en la barra superior: el consejo cambia porque fetch está en build. Carga el consejo una sola vez:
- añade
late Future<String> _tip;al estado - asígnale un valor en
initStateconfetch('/tip') - pasa
_tipaFutureBuilder
Pruébalo tú mismo
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();
},
),
),
),
);
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Datos y red
2Pantallas de carga
Un indicador mientras cargaConoce FutureBuilderCargar una vez en initStateRecargar datos con un botónDeslizar para actualizarPractica por tu cuenta: Compilador de Flutter online