Diferencias entre StatelessWidget y StatefulWidget , cuadro comparativo y alternativas modernas de estado
En Flutter, la interfaz de usuario se construye mediante una estructura de árbol de Widgets. La diferencia fundamental entre un StatelessWidget y un StatefulWidget radica en si el widget necesita recordar y modificar datos a lo largo del tiempo (su estado).
1. StatelessWidget (Sin estado)
Sección titulada «1. StatelessWidget (Sin estado)»- ¿Qué es?: Un widget inmutable. Una vez dibujado en pantalla con sus propiedades iniciales, no puede cambiar por sí mismo.
- Cómo se actualiza: Solo se vuelve a renderizar si su widget padre se reconstruye y le pasa nuevos datos a través de su constructor.
- Ciclo de vida: Prácticamente solo tiene el método
build(). - Casos de uso: Textos fijos, iconos, tarjetas informativas, botones con acciones estáticas, estructuras de maquetación (filas, columnas).
class MiTextoEstatico extends StatelessWidget { // Widget inmutable sin estado propio final String mensaje; // Propiedad inmutable recibida desde el exterior const MiTextoEstatico({super.key, required this.mensaje}); // Constructor constante
@override // Sobreescribe el método build Widget build(BuildContext context) { // Retorna la descripción visual return Text(mensaje); // Renderiza el texto inmutable en pantalla } // Fin del método build} // Fin de la clase MiTextoEstatico2. StatefulWidget (Con estado)
Sección titulada «2. StatefulWidget (Con estado)»- ¿Qué es?: Un widget que mantiene datos que pueden cambiar dinámicamente en respuesta a la interacción del usuario o eventos asíncronos (red, temporizadores).
- Cómo funciona: Se divide en dos clases:
- La clase que hereda de
StatefulWidget(es inmutable y define la configuración). - La clase
State<T>, que contiene las variables mutables y el métodobuild().
- La clase que hereda de
- Mecanismo de cambio: Cuando modificas una variable interna, llamas a
setState(() { ... }), lo que notifica al motor de Flutter que debe redibujar la UI con el nuevo valor. - Ciclo de vida propio: Incluye métodos como
initState()(al crearse),didUpdateWidget()ydispose()(para liberar recursos como controladores o suscripciones). - Casos de uso: Contadores, campos de formulario con validación, interruptores (
Switch), temporizadores, animaciones manuales.
class Contador extends StatefulWidget { // Widget con estado mutable asociado const Contador({super.key}); // Constructor constante de la clase de configuración
@override // Crea la instancia del objeto de estado asociado State<Contador> createState() => _ContadorState(); // Vincula con su clase de estado} // Fin de la clase Contador
class _ContadorState extends State<Contador> { // Clase que retiene el estado dinámico int _conteo = 0; // Variable de estado mutable que persiste en memoria
@override // Sobreescribe build para redibujar ante cambios Widget build(BuildContext context) { // Retorna la UI actualizada según el estado return ElevatedButton( // Botón interactivo onPressed: () { // Callback ejecutado al presionar setState(() { // Notifica al motor que el estado ha cambiado _conteo++; // Incrementa el contador interno }); // Fin de setState }, // Fin de onPressed child: Text('Clics: $_conteo'), // Muestra el valor reactivo actualizado ); // Fin de ElevatedButton } // Fin del método build} // Fin de la clase _ContadorStateResumen comparativo
Sección titulada «Resumen comparativo»| Característica | StatelessWidget |
StatefulWidget |
|---|---|---|
| Estado interno | No tiene (inmutable) | Sí tiene (objeto State) |
Método setState() |
❌ No existe | Sí, dispara el redibujado |
| Consumo de memoria | Muy ligero | Ligeramente mayor (crea dos objetos) |
| Control de ciclo de vida | Solo build() |
initState(), dispose(), etc. |
| Separación lógica/UI | Directo en build |
Lógica en State, UI en build |
3. Alternativas a StatefulWidget
Sección titulada «3. Alternativas a StatefulWidget»Aunque StatefulWidget viene integrado de fábrica en Flutter, en aplicaciones medianas o grandes suele volverse complejo:
- Requiere código repetitivo (boilerplate).
- Puede mezclar lógica de negocio con la vista si no se tiene disciplina.
setState()reconstruye todo el árbol del widget en lugar de solo el nodo que cambió.
Por ello, la comunidad y el equipo de Flutter utilizan varias alternativas modernas:
A. Alternativa nativa sin librerías: ValueNotifier + ValueListenableBuilder
Te permite usar un StatelessWidget y redibujar únicamente la pequeña parte de la UI que depende de ese dato específico:
class ContadorLimpio extends StatelessWidget { // Widget sin estado que aloja un notificador reactivo final ValueNotifier<int> _contador = ValueNotifier<int>(0); // Objeto reactivo nativo de valor único
ContadorLimpio({super.key}); // Constructor del widget
@override // Sobreescribe el método build Widget build(BuildContext context) { // Construye la jerarquía return ValueListenableBuilder<int>( // Escucha cambios solo en _contador valueListenable: _contador, // Conecta con el notificador reactivo builder: (context, valor, child) { // Redibuja ÚNICAMENTE este builder return ElevatedButton( // Botón interactivo onPressed: () => _contador.value++, // Incrementa el valor directamente sin setState child: Text('Clics: $valor'), // Muestra el valor actualizado ); // Fin de ElevatedButton }, // Fin de la función builder ); // Fin de ValueListenableBuilder } // Fin del método build} // Fin de la clase ContadorLimpioB. flutter_hooks (Inspirado en React Hooks)
Sustituye StatefulWidget por un HookWidget. Elimina la necesidad de escribir dos clases, initState y dispose:
class ContadorHook extends HookWidget { // Widget de flutter_hooks sin boilerplate de State const ContadorHook({super.key}); // Constructor constante del widget
@override // Sobreescribe el método build Widget build(BuildContext context) { // Construye la interfaz reactiva final contador = useState(0); // Hook de estado reactivo local en una sola línea return ElevatedButton( // Botón interactivo onPressed: () => contador.value++, // Muta el valor reactivo y redibuja automáticamente child: Text('Clics: ${contador.value}'), // Muestra el conteo actual ); // Fin de ElevatedButton } // Fin del método build} // Fin de la clase ContadorHookC. Gestores de Estado Modernos (Separar UI de Lógica)
Para gestionar estados compartidos entre varias pantallas o que interactúan con APIs:
- Riverpod (
ConsumerWidget): Actualmente el estándar moderno más popular. Seguro en tiempo de compilación, no depende del árbol de widgets (BuildContext) y es muy fácil de testear. - BLoC / Cubit (
BlocBuilder): Basado en Streams y eventos. Es el preferido en entornos empresariales por su arquitectura estricta y separación limpia. - Signals (
flutter_signals): Basado en reactividad por señales (similar a Angular o SolidJS). Extremadamente rápido y con una sintaxis minimalista. - Provider: El gestor clásico recomendado históricamente por el equipo de Flutter.