> For the complete documentation index, see [llms.txt](https://ecm-pmdm-flutter.gitbook.io/1.-introduccion-a-flutter/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ecm-pmdm-flutter.gitbook.io/1.-introduccion-a-flutter/4.-conceptos-fundamentales-en-flutter/ciclo-de-vida/ciclo-de-vida-de-los-widgets.md).

# Ciclo de Vida de los Widgets

![](/files/LaST2ValkpZGp5rMLd8T)

## Ciclo de Vida StatelessWidget

![](/files/REqOCFCrMoTRInCxPU1I)

Widget **inmutable**.  El método `build()`  se llamará en estos casos:

* Cuando el widget se **inserta** por **primera** **vez** en el **árbol** de widgets,&#x20;
* Cuando el widget **padre** **cambia** su configuración: Si el widget padre se reconstruye y pasa nueva información (nuevos valores en el constructor) al StatelessWidget, se crea una nueva instancia de este último y, por lo tanto, se llama a su constructor seguido de `build()`.
* Cuando un [**InheritedWidget**](https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html) del cual depende también **cambia**: Si el StatelessWidget utiliza datos de un InheritedWidget (como Theme.of(context) o MediaQuery.of(context)), y ese InheritedWidget cambia, el framework automáticamente reconstruirá los widgets dependientes, llamando a su método `build()`.

## Ciclo de Vida StatefulWidget

![Explicación: https://medium.flutterdevs.com/app-lifecycle-in-flutter-c248d894b830](/files/r6mEb67xkK6xtLZDEIUw)

<mark style="color:blue;">**createState()**</mark>:  Se llama cuando creamos un **nuevo** StatefulWidget.  Se encarga de crear el estado mutable para este widget instanciando el objeto State asociado a este widget.

<mark style="color:blue;">**initState()**</mark>:  Se llama después del constructor y **sólo** **una** **vez** para cada objecto State.  Aquí podremos inicializar datos, listeners, etc.

**didChangeDependencies()**:  Se llama después de initState() y también cuando se actualiza algún objeto del cual dependa, por ejemplo un InheritedWidget u otras dependencias (cambio de tema, orientación del dispositivo, etc.) &#x20;

> `build()` se ejecutará de forma inmediata tras `didChangeDependencies()`, así que raramente lo implementaremos. A no ser que tengamos un **proceso** **costoso**, como obtener datos de un servidor en red, y que no se ha de hacer en cada build(), sino sólo cuando cambia el InheritedWidget.

<mark style="color:blue;">**build()**</mark><mark style="color:blue;">:</mark>  Devuelve el Widget que se mostrará en pantalla.  **Se** **llama** de forma **frecuente** (después de iniState(), tras setState(),....) cuando se necesita renderizar los UI widgets en pantalla.  Este método **solo debe encargarse de construir el widget**, nada más.   El framework se encargará de **optimizar** **su** **inserción** en el árbol de widgets.

<mark style="color:blue;">**didUpdateWidget**</mark><mark style="color:blue;">()</mark>: Se llama **siempre** que se **cambia** el **Widget** **asociado** a este objeto State por un nuevo Widget del **mismo&#x20;*****runtimeType*****&#x20;y&#x20;*****key*** que el anterior.  El framework asocia el objeto State con el nuevo Widget.  **Después** de este método, **se** **llama** **siempre** **a&#x20;*****build().*** &#x20;

> <mark style="color:orange;">Deberemos</mark> <mark style="color:orange;"></mark><mark style="color:orange;">**sobrescribir**</mark> <mark style="color:blue;">didUpdateWidget</mark> <mark style="color:orange;">para</mark> <mark style="color:orange;"></mark><mark style="color:orange;">**actualizar**</mark> <mark style="color:orange;"></mark><mark style="color:orange;">correctamente el</mark> <mark style="color:orange;"></mark><mark style="color:orange;">**estado**</mark> <mark style="color:orange;"></mark><mark style="color:orange;">con los datos del nuevo widget que se ha creado (o seguiremos mostrando el estado con los datos</mark> <mark style="color:orange;"></mark>*<mark style="color:orange;">del anterior widget)</mark>*

{% hint style="info" %}
<https://api.flutter.dev/flutter/widgets/State/didUpdateWidget.html>

"If the parent widget rebuilds and request that this location in the tree update to display a new widget with the same [runtimeType](https://api.flutter.dev/flutter/widgets/State/dart-core/Object/runtimeType.html) and [Widget.key](https://api.flutter.dev/flutter/widgets/State/widgets/Widget/key.html), the framework will update the [widget](https://api.flutter.dev/flutter/widgets/State/widgets/State/widget.html) property of this [State](https://api.flutter.dev/flutter/widgets/State/widgets/State-class.html) object to refer to the new widget and then call this method with the previous widget as an argument."
{% endhint %}

<mark style="color:blue;">**setState()**</mark>:  Es la forma de **notificar** al framework de Flutter que los datos, el estado, han cambiado y que este widget debe **reconstruirse**.  Este método toma como argumento una función callback que se encarga de actualizar los datos (ha de ser un proceso rápido).

**deactivate()**:  Se llama cuando **momentáneamente** se **elimina** este objeto State **del** **árbol** de **widgets** (los objetos State pueden moverse de lugar en el árbol), però podría ser reinsertado antes de que acabe el *frame* actual.&#x20;

<mark style="color:blue;">**dispose()**</mark>**:**  Se llama cuando este objeto State **se** **va** a **eliminar** de forma **permanente** del árbol de widgets.  En este método es donde deberíamos cancelar animaciones, streams, cerrar conexiones, etc.

{% hint style="info" %}
Más información:

<https://medium.com/@resand/ciclo-de-vida-de-flutter-para-desarrolladores-android-e-ios-4bc4dfcd7169>

<https://levelup.gitconnected.com/flutter-stateful-widget-lifecycle-2c820f93e093>
{% endhint %}

<details>

<summary><strong>Ejemplo para probar ...</strong>  </summary>

<figure><img src="/files/IpI4yEZrIFwf48Sxq7y8" alt="" width="188"><figcaption></figcaption></figure>

{% code lineNumbers="true" fullWidth="true" expandable="true" %}

```dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int _value = 0; // Initial value for the counter
  ThemeData _myTheme = ThemeData.light();

  void _changeTheme() {
    setState(() {
      // Toggle between light and dark theme
      if (_myTheme.brightness == Brightness.dark) {
        _myTheme = ThemeData.light();
      } else {
        _myTheme = ThemeData.dark();
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: _myTheme,
      home: Scaffold(
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              IconButton(
                onPressed: _changeTheme,
                icon: Icon(
                  _myTheme.brightness == Brightness.dark
                      ? Icons.light_mode
                      : Icons.dark_mode,
                ),
                color: _myTheme.brightness == Brightness.dark
                    ? Colors.yellow.shade300
                    : Colors.blue.shade300,
              ),

              const Text('Enter the initial counter value:'),

              TextField(
                textAlign: TextAlign.center,
                keyboardType: TextInputType.number, // Restrict to numbers

                onChanged: (String value) {
                  setState(() {
                    // Safely parse the integer, defaulting to 0 if invalid
                    _value = int.tryParse(value) ?? 0;
                  });
                },
              ),
              const SizedBox(height: 40), // Spacing between input and counter
              // MyCounter is rebuilt with the new _value whenever setState in MyApp occurs
              _myTheme.brightness == Brightness.dark
                  ? Text('COUNTER ONLY AVAILABLE IN LIGHT MODE')
                  : MyCounter(initValue: _value),
            ],
          ),
        ),
      ),
    );
  }
}

class MyCounter extends StatefulWidget {
  MyCounter({required this.initValue, super.key}) {
    print('MyCounter - constructor');
  }

  final int initValue;

  @override
  State<MyCounter> createState() => _MyCounterState();
}

class _MyCounterState extends State<MyCounter> {
  late int _counter;

  @override
  void initState() {
    print('MyCounter - initState');

    super.initState();
    _counter = widget.initValue; // Initialize counter with the passed value
  }

  @override
  void didUpdateWidget(MyCounter oldWidget) {
    print('MyCounter - didUpdateWidget');

    super.didUpdateWidget(oldWidget);

    // If the parent widget provides a new initValue, update the internal _counter
    if (widget.initValue != oldWidget.initValue) {
      _counter = widget.initValue;
    }
  }

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

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print('MyCounter - didChangeDependencies');
  }

  @override
  void deactivate() {
    super.deactivate();

    print('MyCounter - deactivate');
  }

  @override
  void dispose() {
    super.dispose();
    print('MyCounter - dispose');
  }

  @override
  Widget build(BuildContext context) {
    print('MyCounter - build');

    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        const Text('Has pulsado el botón #:'),
        Text('$_counter', style: Theme.of(context).textTheme.headlineMedium),

        ElevatedButton(
          onPressed: _incrementCounter,
          style: ElevatedButton.styleFrom(
            padding: const EdgeInsets.all(16.0),
            shape: const CircleBorder(),
          ),
          child: const Icon(Icons.add, size: 24),
        ),
      ],
    );
  }
}

```

{% endcode %}

</details>

#### <mark style="color:blue;">Actividad de vídeo:  ¿Cómo renderiza Flutter los widgets?</mark>

<figure><img src="/files/4n6jIJEwUpngibHbzDmh" alt="" width="375"><figcaption><p>The 3 Widget Tree</p></figcaption></figure>

{% stepper %}
{% step %}

#### Visualiza

**Visualiza** atentamente los siguientes **vídeos** donde:

* Se describe **cómo** **trabaja** **Flutter** **internamente** (lo cual, le permite ser muy eficiente)
* Se explica la relación entre las jerarquías **Widget**, **Element** y **RenderObject**.

**VIDEO 1: (7 mins):  How Flutter works? The three widget tree**

* <https://www.youtube.com/watch?v=xiW3ahr4CRU>

**VÍDEO 2 (26 mins):  How Flutter render widgets?**&#x20;

* <https://www.youtube.com/watch?v=996ZgFRENMs&list=PLjxrf2q8roU3wk7CDw4RfV3mEwOJbjx1k>
  {% endstep %}

{% step %}

#### Responde

Tras visualizar los **vídeos,** **responde** las siguientes **preguntas** y **comprueba** tus respuestas:

{% tabs %}
{% tab title="Responde las siguientes cuestiones" %}

1. ¿Cuáles son los tres árboles principales en la arquitectura de Flutter?
   * a) Widget, Bloc, Model
   * b) Widget, Element, RenderObject
   * c) Bloc, Provider, State
   * d) Build, Render, Widget
2. ¿Qué tipo de widget se utiliza en Flutter cuando se requiere recursos de larga duración, como animaciones o controladores de texto?
   * a) StatelessWidget
   * b) InheritedWidget
   * c) StatefulWidget
   * d) RenderObjectWidget
3. ¿Qué objeto sirve como “pegamento” entre los widgets y el sistema de rendering en Flutter?
   * a) Widget
   * b) Element
   * c) RenderObject
   * d) Context
4. Cuando el contenido de una app cambia, ¿cuál de los siguientes permanece el mayor tiempo posible para mejorar la eficiencia?
   * a) Widget
   * b) Element
   * c) RenderObject
5. ¿Cómo maneja Flutter el cambio en sus árboles cuando dos widgets del mismo tipo pero con distintas propiedades reemplazan uno al otro?
   * a) Destruye y recrea todos los objetos
   * b) Reutiliza los RenderObjects y Elements cuando puede
   * c) Solo redibuja el widget afectado
   * d) No realiza ningún cambio
6. Explica la diferencia fundamental entre un StatelessWidget y un StatefulWidget en Flutter.
7. ¿Qué sucede a nivel de los árboles de Flutter cuando se reemplaza un widget Padding por un SizedBox?
8. ¿Por qué se utilizan tres árboles (Widget, Element y RenderObject) en lugar de uno solo en Flutter?
9. Describe el ciclo de vida de un widget en términos de su paso por los árboles de Flutter.
10. Da un ejemplo práctico de una situación en la que un widget puede ser recreado muchas veces, pero su Element y RenderObject pueden ser reutilizados
    {% endtab %}

{% tab title="Respuestas" %}

1. ¿Cuáles son los tres árboles principales en la arquitectura de Flutter?\ <mark style="color:green;">**Respuesta**</mark> <mark style="color:green;"></mark> <mark style="color:green;"></mark><mark style="color:green;">b) Widget, Element, RenderObject​</mark>
2. ¿Qué tipo de widget se utiliza en Flutter cuando se requiere recursos de larga duración, como animaciones o controladores de texto?\ <mark style="color:green;">**Respuesta:**</mark> <mark style="color:green;"></mark><mark style="color:green;">c) StatefulWidget​</mark>
3. ¿Qué objeto sirve como “pegamento” entre los widgets y el sistema de rendering en Flutter?\ <mark style="color:green;">**Respuesta:**</mark> <mark style="color:green;"></mark><mark style="color:green;">b) Element​</mark>
4. Cuando el contenido de una app cambia, ¿cuál de los siguientes permanece el mayor tiempo posible para mejorar la eficiencia?\ <mark style="color:green;">**Respuesta:**</mark> <mark style="color:green;"></mark><mark style="color:green;">b) Element​</mark>
5. ¿Cómo maneja Flutter el cambio en sus árboles cuando dos widgets del mismo tipo pero con distintas propiedades reemplazan uno al otro?\ <mark style="color:green;">**Respuesta:**</mark> <mark style="color:green;"></mark><mark style="color:green;">b) Reutiliza los RenderObjects y Elements cuando puede​.</mark>
6. Explica la diferencia fundamental entre un StatelessWidget y un StatefulWidget en Flutter.\ <mark style="color:green;">**Respuesta:**</mark> <mark style="color:green;"></mark><mark style="color:green;">Un StatelessWidget es inmutable y su contenido no cambia durante su ciclo de vida; dependiendo solo de la configuración inicial. Un StatefulWidget, en cambio, tiene un objeto State asociado, que puede mantener datos y cambiar con el tiempo, permitiendo que el widget reaccione a cambios y se reconstruya según sea necesario.​</mark>
7. ¿Qué sucede a nivel de los árboles de Flutter cuando se reemplaza un widget Padding por un SizedBox?\ <mark style="color:green;">**Respuesta:**</mark> <mark style="color:green;"></mark><mark style="color:green;">Flutter destruye el Element y RenderObject asociados al Padding y crea nuevos para el SizedBox, ya que no comparten el mismo tipo y no pueden reutilizar las instancias previas.​</mark>
8. ¿Por qué se utilizan tres árboles (Widget, Element y RenderObject) en lugar de uno solo en Flutter?\ <mark style="color:green;">**Respuesta:**</mark> <mark style="color:green;"></mark><mark style="color:green;">Se utilizan tres árboles para separar las responsabilidades: el árbol de Widgets define la configuración y estructura inmutable, el de Elements administra el ciclo de vida y vinculación de instancias, y el de RenderObjects se encarga mostrar la UI en pantalla (dibujar y  layout), así se optimiza el rendimiento, reutilizando estructura donde sea posible y minimizando reconstrucciones costosas.​</mark>
9. Describe el ciclo de vida de un widget en términos de su paso por los árboles de Flutter.\ <mark style="color:green;">**Respuesta:**</mark> <mark style="color:green;"></mark><mark style="color:green;">Un widget se crea y se añade al árbol de widgets, luego Flutter le pide que cree un Element, que se añade al árbol de elementos. El Element llama a la creación del RenderObject y lo conecta al árbol de renderizado. Cuando los datos cambian, Flutter decide si puede reutilizar los elementos y render objects o si necesita crear nuevos, dependiendo del tipo y las claves.​</mark>
10. Da un ejemplo práctico de una situación en la que un widget puede ser recreado muchas veces, pero su Element y RenderObject pueden ser reutilizados.\ <mark style="color:green;">**Respuesta:**</mark> <mark style="color:green;"></mark><mark style="color:green;">Cuando se actualiza el texto de un widget Text muchas veces (por ejemplo, al pulsar un botón se incrementa un contador y se actualiza el texto mostrado en pantalla), se recrean muchas instancias de ese widget Text, pero Flutter reutiliza el mismo Element y RenderObject asociados a ese nodo en el árbol, optimizando el rendimiento.</mark>

{% endtab %}
{% endtabs %}

{% endstep %}
{% endstepper %}
