¿Para qué sirven `FutureBuilder` y `StreamBuilder` y cuándo usar cada uno?
Ver respuesta — intenta responderla en voz alta primero
Ambos conectan datos asíncronos con la UI. FutureBuilder construye la interfaz a partir de un Future (un solo resultado, como una petición HTTP). StreamBuilder la construye a partir de un Stream (varios valores en el tiempo, como datos en vivo). Cada uno reconstruye el widget según el estado del dato asíncrono (cargando, con datos, con error).
En vez de manejar el estado asíncrono a mano con setState, estos widgets lo hacen por ti:
FutureBuilder: le das unFuturey unbuilder. Elbuilderrecibe unsnapshotcon el estado. Úsalo para operaciones que dan un resultado: cargar un perfil, leer un archivo.StreamBuilder: le das unStream. Reconstruye cada vez que el stream emite un valor. Úsalo para datos que cambian continuamente: ubicación, mensajes de chat, un contador en vivo.
El snapshot te dice: si hay error (hasError), si hay datos (hasData), o si sigue esperando (connectionState == waiting). Con eso decides qué mostrar.
import 'package:flutter/material.dart';
Future<String> cargarNombre() async {
await Future.delayed(const Duration(seconds: 1));
return "Mike";
}
class Perfil extends StatelessWidget {
const Perfil({super.key});
@override
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: cargarNombre(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator(); // cargando
}
if (snapshot.hasError) {
return Text("Error: ${snapshot.error}"); // falló
}
return Text("Hola, ${snapshot.data}"); // listo
},
);
}
}
Crear el Future dentro del build directamente en el parámetro future:. Como build se ejecuta muchas veces, se dispararía la operación asíncrona una y otra vez en cada reconstrucción. Lo correcto es crear el Future una sola vez: guardarlo en una variable de estado (initState) o usar un StatefulWidget. El mismo cuidado aplica al Stream de StreamBuilder.
"
FutureBuilderyStreamBuilderconectan datos asíncronos con la UI sin que yo maneje elsetStatea mano.FutureBuilderes para un solo resultado, como una petición HTTP;StreamBuilderpara datos que cambian con el tiempo, como un chat o la ubicación. Ambos me dan unsnapshotcon el estado: cargando, con datos o con error, y según eso muestro un spinner, el contenido o un mensaje de error. Un cuidado importante es no crear elFuturedentro delbuild, porque se relanzaría en cada reconstrucción; lo creo una vez eninitState."
¿Por qué es un problema escribir future: miFuncionAsync() directamente en el build?
Ver respuesta
Porque build se llama muchas veces (en cada reconstrucción), y cada vez se crearía un Future nuevo, relanzando la operación asíncrona (por ejemplo, repitiendo la petición de red) y reiniciando el estado de carga. La solución es crear el Future una sola vez, típicamente guardándolo en una variable en initState de un StatefulWidget, y pasar esa variable al FutureBuilder.