¿Qué causa que un widget se reconstruya y cómo evitas reconstrucciones innecesarias?
Ver respuesta — intenta responderla en voz alta primero
Un widget se reconstruye cuando su padre se reconstruye, cuando llamas a setState, o cuando cambia un InheritedWidget del que depende. Para evitar reconstrucciones innecesarias: usa constructores const, extrae subárboles a widgets separados, acota el alcance de setState y usa el hijo (child) que no se reconstruye en widgets como AnimatedBuilder.
Reconstruir (build) no pinta pixeles directamente; genera la descripción del árbol. Pero si reconstruyes mucho y de más, gastas CPU y puedes causar jank (saltos en la animación). Las causas de un rebuild:
- El padre se reconstruye: por defecto arrastra a sus hijos.
setState: reconstruye elStateque lo llamó.- Cambia un
InheritedWidgetdel que el widget depende (por ejemplo,Theme).
Estrategias para reducirlos:
const: subárboles que no cambian no se reconstruyen.- Extraer widgets: mueve la parte que cambia a su propio widget pequeño, para que solo ese se reconstruya.
- Acotar
setState: que elsetStateviva en el widget más pequeño posible, no en la pantalla entera. - Parámetro
child: enAnimatedBuilder/ValueListenableBuilder, elchildse construye una vez y se pasa sin reconstruirse.
import 'package:flutter/material.dart';
// El truco del "child": la parte cara (el Text) se construye UNA vez
// y no se reconstruye en cada frame de la animación.
class Pulsante extends StatelessWidget {
const Pulsante({super.key, required this.animacion});
final Animation<double> animacion;
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animacion,
// Este child NO se reconstruye en cada frame:
child: const Text("No me reconstruyo cada frame"),
builder: (context, child) {
return Opacity(
opacity: animacion.value,
child: child, // reutilizo el child construido una sola vez
);
},
);
}
}
Llamar a setState en el widget más alto (por ejemplo, en toda la pantalla) por un cambio que solo afecta a un botoncito. Eso reconstruye media UI cuando bastaría con reconstruir ese botón. También es común no usar const y provocar reconstrucciones evitables en cada frame. Para diagnosticar, se usan las Flutter DevTools (el Performance y el rebuild counter).
"Un widget se reconstruye cuando su padre lo hace, cuando llamo a
setState, o cuando cambia unInheritedWidgetdel que depende, como elTheme. Para evitar rebuilds innecesarios uso constructoresconst, extraigo la parte que cambia a su propio widget pequeño para acotar el rebuild, pongo elsetStateen el widget más específico posible, y aprovecho el parámetrochilddeAnimatedBuilderpara no reconstruir lo que no cambia. Cuando algo va lento, lo mido con las DevTools antes de optimizar a ciegas."
¿Para qué sirve el parámetro child en un AnimatedBuilder?
Ver respuesta
Sirve para construir una sola vez la parte del subárbol que no depende de la animación, y reutilizarla en cada frame. El builder se ejecuta en cada frame de la animación, pero el child se pasa ya construido, así que evitas reconstruir esa porción 60 veces por segundo. Es una optimización clave en animaciones.