¿Cuáles son los métodos del ciclo de vida de un `State` y para qué sirve cada uno?
Ver respuesta — intenta responderla en voz alta primero
Los principales son: initState (se llama una vez al crear el estado), didChangeDependencies (cuando cambian dependencias heredadas), build (cada vez que hay que dibujar), didUpdateWidget (cuando el widget se reconfigura), setState (para pedir una reconstrucción) y dispose (una vez al destruir, para liberar recursos).
El orden típico de vida de un State:
initState(): se ejecuta una sola vez, al insertarse en el árbol. Aquí inicializas controladores, suscripciones o peticiones iniciales. No puedes usarcontextparaInheritedWidgetde forma segura todavía.didChangeDependencies(): justo después deinitStatey cada vez que cambia unInheritedWidgetdel que dependes. Buen lugar para leer unProviderque puede cambiar.build(): construye la UI. Se llama muchas veces; debe ser rápido y sin efectos secundarios.didUpdateWidget(old): cuando el widget padre se reconstruye y pasa una nueva configuración. Aquí comparas conoldWidgetpara reaccionar a cambios de parámetros.setState(): marca el estado como "sucio" y agenda unbuild.dispose(): se ejecuta una vez, al retirar el widget del árbol para siempre. Aquí liberas recursos: cancelas streams,dispose()de controladores, etc.
import 'package:flutter/material.dart';
class Reloj extends StatefulWidget {
const Reloj({super.key});
@override
State<Reloj> createState() => _RelojState();
}
class _RelojState extends State<Reloj> {
late final TextEditingController _controlador;
@override
void initState() {
super.initState();
_controlador = TextEditingController(); // inicializo recursos
print("initState: solo una vez");
}
@override
void didUpdateWidget(covariant Reloj oldWidget) {
super.didUpdateWidget(oldWidget);
print("El widget se reconfiguró");
}
@override
void dispose() {
_controlador.dispose(); // libero recursos SIEMPRE
print("dispose: limpieza final");
super.dispose();
}
@override
Widget build(BuildContext context) {
return TextField(controller: _controlador);
}
}
No liberar recursos en dispose(). Si creas un TextEditingController, un AnimationController, un Timer o una suscripción a un Stream y no los liberas, generas fugas de memoria y advertencias en consola. Regla: todo lo que inicializas en initState (o que tenga dispose) debe limpiarse en dispose.
"El ciclo empieza con
initState, que corre una sola vez y donde inicializo controladores y suscripciones. LuegodidChangeDependenciescuando cambian dependencias heredadas.buildse llama muchas veces para dibujar y debe ser puro y rápido.didUpdateWidgetcorre cuando el padre me pasa una configuración nueva.setStateagenda una reconstrucción. Ydisposecorre una vez al final, donde libero todo lo que abrí para evitar fugas de memoria. La regla clave es que todo lo que abro eninitStatelo cierro endispose."
¿Cuántas veces se ejecuta initState durante la vida de un State?
Ver respuesta
Exactamente una vez, cuando el State se inserta en el árbol por primera vez. Aunque el widget se reconstruya muchas veces (llamando a build repetidamente), initState no se vuelve a ejecutar. Su contraparte, dispose, también corre una sola vez, al retirar el widget del árbol.