flutter-stateless-vs-stateful

StatelessWidget y StatefulWidget en Flutter

  • 4 min

Un widget con estado es un componente que recuerda información y puede redibujarse.

Ya hemos creado nuestra primera App y sabemos que “todo es un Widget”. Pero pronto te darás cuenta de que hay dos tipos de Widgets y que la elección entre uno y otro define cómo se comporta tu aplicación.

Hablamos de StatelessWidget y StatefulWidget.

Entender esta diferencia te permitirá decidir dónde debe vivir el estado y qué parte de la interfaz necesita reconstruirse.

El concepto de estado

Antes de ver el código, definamos qué es el Estado.

El estado es la información que puede cambiar a lo largo del tiempo en tu Widget y que afecta a cómo se ve en pantalla.

  • El texto de un contador (0, 1, 2…).
  • Si un checkbox está marcado o no.
  • El color de un botón cuando lo pulsas.

Si un dato cambia y quieres que la pantalla se actualice para reflejar ese cambio, eso es Estado.

StatelessWidget

Un StatelessWidget es inmutable: sus propiedades no cambian durante la vida de esa instancia. Sin embargo, Flutter puede sustituirla por otra configuración y volver a ejecutar su método build.

Imagínalo como una fotografía. Una vez revelada, la foto no cambia. Si quieres que la persona en la foto sonría, no puedes modificar la foto: tienes que tirar la foto vieja y tomar una nueva.

¿Cuándo usarlo?

Cuando la parte de la interfaz que estás describiendo no depende de ninguna interacción del usuario ni de datos que cambien internamente.

  • Un icono.
  • Un texto fijo (“Título de la App”).
  • Un contenedor de color.

Estructura

Es muy simple. Solo sobrescribimos el método build.

class MiBotonSimple extends StatelessWidget {
  // Las propiedades DEBEN ser final (inmutables)
  final String texto;

  const MiBotonSimple({required this.texto});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(10),
      color: Colors.blue,
      child: Text(texto),
    );
  }
}
Copied!

Flutter es extremadamente rápido creando y destruyendo StatelessWidgets. No tengas miedo de usarlos y anidarlos.

StatefulWidget

Un StatefulWidget también es inmutable, pero delega la información mutable en un objeto State separado. Ese estado puede cambiar en respuesta a pulsaciones, datos de internet o temporizadores.

Imagínalo como un vídeo o un robot. Puede moverse, cambiar de color y reaccionar.

La arquitectura de dos clases

Aquí es donde los principiantes se lían. Un StatefulWidget no es una sola clase, son dos:

  1. El Widget: Es inmutable (como el Stateless). Solo sirve de configuración.
  2. El Estado (State): Es donde vive la lógica y los datos mutables. Esta clase persiste aunque la pantalla se redibuje.

¿Por qué dos clases? Por rendimiento. Flutter puede reconstruir la UI (el Widget) mil veces por segundo, pero mantiene el objeto State en memoria para no perder tus datos (como el valor del contador).

Estructura y setState

Vamos a ver el ejemplo clásico del contador. Fíjate en el método setState.

// 1. La clase Widget (Pública e inmutable)
class ContadorWidget extends StatefulWidget {
  @override
  _ContadorWidgetState createState() => _ContadorWidgetState();
}

// 2. La clase State (Privada _ y Mutable)
class _ContadorWidgetState extends State<ContadorWidget> {
  
  // Aquí SÍ podemos tener variables que no sean final
  int _contador = 0;

  void _incrementar() {
    // setState avisa a Flutter de que algo cambió
    setState(() {
      _contador++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text('Clicks: $_contador'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementar, // Llamamos a la función al pulsar
        child: Icon(Icons.add),
      ),
    );
  }
}
Copied!

El método setState()

Cuando cambias el valor de _contador++, Dart actualiza la variable, pero la pantalla no se entera. La pantalla sigue mostrando “0”.

Al envolver el cambio dentro de setState( () { ... } ), le estás diciendo a Flutter:

“He cambiado un dato que afecta a la interfaz. Programa una reconstrucción de este subárbol con los datos actualizados”.

Si olvidas el setState, tu variable cambiará, pero la interfaz seguirá congelada.

¿Cuál elijo?

Esta es la regla de oro que usamos nosotros:

  1. Empieza siempre con un StatelessWidget. Es más ligero y fácil de leer.
  2. ¿Necesitas que ese widget cambie (color, texto, forma) cuando el usuario lo toca? -> Conviértelo a StatefulWidget.
  3. ¿El cambio viene de fuera (el padre le pasa datos nuevos)? -> Quédate en StatelessWidget (el padre se encargará de reconstruirlo).