StatelessWidget vs StatefulWidget: ¿Cuál y cuándo usar?

Edgar AldairEdgar Aldair
8 min read

Cuando comenzamos a desarrollar en Flutter, una de las primeras cosas que aprendemos es que todo en Flutter es un widget. Desde un botón hasta la estructura completa de una pantalla, podría decirse que los widgets son los bloques fundamentales con los que se construyen las aplicaciones. Sin embargo tan pronto como comienzas a desarrollar tu primera app, te encuentras con una decisión importante: ¿Debería usar un StatelessWidget o un StatefulWidget? Quizá te parezca una decisión poco importante, pero ¿Realmente afecta?

Es una pregunta que muchos se hacen, y la respuesta puede parecer confusa al principio. Por lo que hoy exploraremos a fondo las diferencias entre estos dos tipos de widgets, profundizaremos en casos prácticos de uso y resolveremos las dudas más comunes para que tomes decisiones informadas en tus proyectos.

El núcleo de Flutter: Los widgets

Como mencionamos arriba, en Flutter, un widget es cualquier elemento visual o funcional que ves en la pantalla. Pero no todos los widgets son iguales. Algunos son inmutables y están diseñados para mostrar información que no cambia, mientras que otros pueden actualizarse dinámicamente en respuesta a las acciones del usuario o cambios en los datos.

Aquí es donde entra en juego los StatelessWidgets y los StatefulWidgets, de forma resumida:

  • Los StatelessWidgets son estáticos, perfectos para elementos que no necesitan actualizarse, de ahi viene su nombre State (estado) less (sin); sin estado

  • Los StatefulWidgets, en cambio, permiten manejar un estado mutable, ideal para crear interactividad. como su nombre lo dice State (estado) full (completo); estado completo

Esta distinción, aunque es simple en la teoría, puede ser un desafío si no se comprende bien, así que profundizaremos en cada uno de estos a continuación.

¿Qué es un StatelessWidget?

Como mencionamos en la definición un StatelessWidget es un widget sin estado, esto significa que una vez creado, no puede cambiar. Su apariencia, contenido y configuración son fijos mientras la app se ejecuta.

Por ejemplo, si estás mostrando un texto estático o un ícono que no cambia, un StatelessWidget es todo lo que necesitas. Al ser inmutables, son más eficientes y requieren menos recursos del sistema. En un ejemplo práctico podría verse algo así, donde la clase extiende de un StatelessWidget y pintamos un widget al centro de la pantalla el cual no va a cambiar:

import 'package:flutter/material.dart';

class MyStatelessWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('¡Hola, Edgar Aldair!'),
    );
  }
}

En este caso, no hay necesidad de manejar estado. Ya que esto simplemente es una pantalla estática, donde el texto se renderiza una vez y permanece igual. Con todo esto surgen algunas preguntas básicas que nos debemos hacer, como ¿Cuáles son las ventajas de usar StatelessWidget? Bien, para este punto debemos saber que al usar un StatelessWidget nos dará ciertas ventajas como:

  • Es más eficiente en términos de rendimiento.

  • El código es más simple y fácil de mantener.

  • Es Ideal para elementos estáticos como íconos, textos o imágenes.

Así que comprendido esto, pasemos al otro lado de la moneda, los StatefulWidgets.

¿Qué es un StatefulWidget?

Los StatefulWidgets, por otro lado, son dinámicos. Es la mejor opción cuando necesitas que algo en tu widget cambie durante la ejecución de la app. Por ejemplo; un contador que aumenta al hacer clic en un botón, una barra de progreso o un formulario que acepta entrada del usuario. Estos son un poquito más complejos de entender, pero en este artículo vamos a irlo viendo paso a paso para que logres entender a la perfección como es que funcionan. Un StatefulWidget se divide en dos partes:

  1. La clase del widget (StatefulWidget) que define su estructura básica.

  2. La clase del estado (State) que maneja el comportamiento mutable y los datos asociados al widget.

Por ejemplo podemos crear un botón que aumente un contador al hacer click, no te agobies si no entiendes algunas lineas de código, mas adelante veremos que hace cada linea a manera que puedas comprenderlo:

import 'package:flutter/material.dart';

class MyCounter extends StatefulWidget {
  @override
  _MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}

class _MyCounterState extends State<MyCounter> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text('Contador: $_counter'),
        ElevatedButton(
          onPressed: _incrementCounter,
          child: Text('Incrementar'),
        ),
      ],
    );
  }
}

Vamos a desmenuzar cada parte del código para que quede claro:

import 'package:flutter/material.dart';

Esta línea importa la biblioteca material.dart, que contiene widgets, temas y utilidades necesarias para construir una interfaz de usuario al estilo de Material Design en Flutter. Sin esta línea, no podríamos usar widgets como por ejemplo Column, Text, ElevatedButton u otros.

class MyCounter extends StatefulWidget {
  @override
  _MyCounterState createState() => _MyCounterState();
}

En estas lineas pasan 3 cosas importantes:

class MyCounter extends StatefulWidget

    • Aquí definimos un nuevo widget llamado MyCounter.

      • Este widget es de tipo StatefulWidget, lo que significa que puede mantener y gestionar un estado mutable, como ya vimos antes.
  1. @override

    • Es una anotación que indica que estamos sobrescribiendo un método o funcionalidad ya existente. Aquí, sobrescribimos el método createState.

Es como decirle a Dart, "Voy a usar un método ya existente, pero lo voy a personalizar según lo que necesite aquí."

  1. _MyStatefulWidgetState createState() => _MyStatefulWidgetState();

    • Este método crea y devuelve una instancia de la clase _MyStatefulWidgetState, que es donde se define el estado y el comportamiento dinámico de este widget.

Cada vez que creas un StatefulWidget, necesitas decirle a Flutter qué clase gestionará su estado. Este es el propósito de createState.

En este caso, le decimos:
**"**Para MyCounter, usa la clase _MyCounterState para manejar el estado."

Ahora viene una pregunta: ¿Qué pasa si no usamos override?

  • En primera instancia aunque el código funcionará, Dart no sabrá que estás sobrescribiendo un método, y podrías cometer errores difíciles de rastrear.

  • Usarlo es una buena práctica porque mejora la legibilidad y detecta posibles errores en tiempo de compilación.

Bien continuemos con el código,

class _MyCounterState extends State<MyCounter> {
  int _counter = 0;
  1. class _MyCounterWidgetState

    Esta es la clase que define el estado y la lógica del widget y el nombre comienza con un guion bajo (_) porque, en Dart, eso indica que la clase es privada (solo puede usarse dentro de este archivo).

  2. extends State<MyCounter>

    Indica que esta clase manejará el estado del widget MyStatefulWidget. Aquí es donde implementaremos la lógica de negocio, las variables y los métodos que controlan la apariencia y el comportamiento del widget.

  3. int _counter = 0;

    Declaramos una variable privada _counter que almacenará el número actual del contador, nuevamente el guion bajo (_) hace que la variable sea privada, es decir, que solo sea accesible dentro de esta clase.

     void _incrementCounter() {
       setState(() {
         _counter++;
       });
     }
    
  4. void _incrementCounter()

    Es un método privado (por el guion bajo) que no devuelve ningún valor (void). Su función es aumentar el valor de _counter en 1 cada vez que se llame.

  5. setState(() { ... });

    Este método notifica a Flutter que el estado del widget ha cambiado. Asi que dentro de setState, actualizamos el valor de _counter. Después de esto, Flutter reconstruye automáticamente la UI para reflejar el nuevo valor, sin setState, aunque cambiemos el valor de _counter, la UI no se actualizará.

     @override
     Widget build(BuildContext context) {
    

    El método build es obligatorio para cualquier widget en Flutter. Es llamado cada vez que se necesita dibujar (o volver a dibujar) la UI del widget, BuildContext proporciona información sobre la posición del widget dentro del árbol de widgets de Flutter.

return Column(
  mainAxisAlignment: MainAxisAlignment.center,
  children: [
    Text('Contador: $_counter'),
    ElevatedButton(
      onPressed: _incrementCounter,
      child: Text('Incrementar'),
    ),
  ],
);
  1. return Column(...)

    Usamos un widget Column para organizar otros widgets en una disposición vertical.

  2. mainAxisAlignment: MainAxisAlignment.center

    Centra los widgets hijos verticalmente en la pantalla.

  3. children: [ ... ]

    Aquí definimos los widgets hijos que estarán dentro de la columna.

  4. Text('Contador: $_counter')

    Muestra un texto que incluye el valor actual de _counter y la interpolación de cadenas ($_counter) inserta el valor actual de la variable dentro del texto.

  5. ElevatedButton(...)

    Es un botón elevado el cual contiene el método onPressed: _incrementCounter este es el callback que se ejecuta cuando el botón es presionado. En este caso, llama al método _incrementCounter para aumentar el contador.

Podríamos resumir que el widget comienza como un StatefulWidget. Su clase de estado maneja el comportamiento dinámico y define un contador counter. Cuando presionamos el botón, se llama a incrementCounter, este incrementa el contador y usa setState para notificar a Flutter que debe redibujar la UI. Flutter reconstruye el widget con el nuevo valor de _counter, y el texto del contador se actualiza en pantalla.

Diferencias clave entre StatelessWidget y StatefulWidget

Como ya vimos a lo largo del artículo, las diferencias son notables entre cada tipo de widget, así que podemos ver las diferencias claves a continuación:

CaracterísticaStatelessWidgetStatefulWidget
EstadoNo tiene estado.Tiene estado mutable.
RendimientoMás eficiente.Menos eficiente.
Uso típicoContenido estático.Elementos interactivos.

Antes de finalizar este artículo no debemos olvidarnos de algo muy importante al trabajar con estos widgets, me refiero a los errores.

Errores comunes y cómo evitarlos

  1. Usar StatefulWidget para contenido estático:
    Esto desperdicia recursos y complica el código innecesariamente. Si tu widget no cambia, usa StatelessWidget.

  2. No manejar correctamente el estado mutable:
    Siempre usa setState() para notificar a Flutter de cambios en el estado.

Como cosejo si no estás seguro, empieza con StatelessWidget y cambia a StatefulWidget solo si detectas la necesidad de manejar estado mutable.

Dominar la diferencia entre StatelessWidget y StatefulWidget es un paso esencial para cualquier desarrollador de Flutter. Entender cuándo usar cada uno te ayudará a escribir código más eficiente, limpio y fácil de mantener.

Si este artículo te ayudó, compártelo con tus amigos o déjame saber cuál ha sido tu mayor desafío con Flutter. ¡Nos vemos en el siguiente artículo!

0
Subscribe to my newsletter

Read articles from Edgar Aldair directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Edgar Aldair
Edgar Aldair