diegoRodicio

Está documentación está a túa disposición sin ningún custo económico. Sen embargo, para a súa elaboración dedico moito tempo e recursos, polo que agradecería unha colaboración co que consideres oportuno. Gracias.

View Categories

🧠 Xestión de Estado Básica

A xestión de estado é un dos conceptos máis importantes en Flutter. Permite actualizar a interface de usuario cando cambian os datos ou o estado interno da aplicación (como contadores, formularios, listas, preferencias, etc.).

❗ O problema da xestión de estado #

En Flutter, a UI é unha función do estado da túa aplicación. Cando o estado cambia (cada vez que se chama a setState()), Flutter reconstrúe (redeseña) a parte da UI que depende dese estado.

O problema xorde cando o estado que necesitas para unha parte da UI reside nun widget diferente ao que o necesita, ou cando moitos widgets diferentes necesitan acceder e/ou modificar o mesmo anaco de estado.

⚠️ Imaxina un exemplo sinxelo: un contador nunha pantalla.

  • O valor do contador (_valorContador) reside nun StatefulWidget.
  • Se quixeses mostrar ese valor noutro widget totalmente diferente (quizais nunha barra de navegación superior ou nun widget fillo moi anidado), como o pasas sen ter que ir “furando” polos construtores de cada widget intermedio? Ou, se ese outro widget quixese modificar o contador?

🔎 Exemplo típico que se complica #

// Que pasa cando varios widgets necesitan saber o valor deste contador?
int contador = 0;

ElevatedButton(
  onPressed: () {
    setState(() {
      contador++;
    });
  },
  child: Text('Incrementar'),
);

🔎 Exemplo detallado #

Neste exemplo, o estado _contador reside en _PaginaContadorProblemaState. Se moitos outros widgets precisasen acceder ou modificar _contador, terías que pasar valores a través de moitos construtores, o que fai o código difícil de manter e entender.

// Exemplo do problema (código que ilustra o reto, non para replicar directamente)
import 'package:flutter/material.dart';

class PaginaContadorProblema extends StatefulWidget {
  @override
  _PaginaContadorProblemaState createState() => _PaginaContadorProblemaState();
}

class _PaginaContadorProblemaState extends State<PaginaContadorProblema> {
  int _contador = 0; // O estado vive aquí

  void _incrementarContador() {
    setState(() {
      _contador++;
    });
  }

  @override
  Widget build(BuildContext contexto) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Contador: $_contador'), // A barra de navegación necesita o estado
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Valor actual: $_contador'), // Este widget tamén necesita o estado
            ElevatedButton(
              onPressed: _incrementarContador, // Este botón modifica o estado
              child: Text('Incrementar'),
            ),
            // Como pasas _contador ou _incrementarContador a un widget fillo moi anidado?
            // WidgetFilloLongo(contador: _contador, onIncrementar: _incrementarContador)
          ],
        ),
      ),
    );
  }
}

🧩 Importante: Para solucionar isto, Flutter ofrece patróns como o levantamento de estado, o uso de InheritedWidget, e solucións máis avanzadas como Provider, Riverpod, Bloc

📤 Levantamento de estado (“lifting state up”) #

O patrón lifting state up consiste en mover o estado (por exemplo, unha variable que cambia) a un widget pai para que poida ser compartido entre varios fillos.

🧪 Exemplo: Un contador compartido #

🔗 Ver o código en DartPad

🧪 Outro exemplo: Un contador compartido #

Neste exemplo, o estado _valorContador reside no _PaginaContadorRefactorizadaState. O BotonIncrementar (o fillo) non ten idea de como se incrementa o contador; simplemente chama á función aoPulsar que lle foi pasada polo seu pai. O pai, ao recibir a chamada, actualiza o seu propio estado e, a través de setState, provoca que tanto el como os seus fillos dependentes se redeseñen co novo valor.

🔗 Ver o código en DartPad

🧬 InheritedWidget (concepto) #

⚠️ Nota: Mentres que o “levantamento de estado” funciona ben para relacións pai-fillo directas ou con poucos niveis de anidamento, pode volverse tedioso se moitos widgets en diferentes partes da árbore de widgets necesitan acceder ao mesmo estado sen ser fillos directos. Aquí é onde entra o concepto de InheritedWidget.

InheritedWidget é unha clase base que permite compartir estado eficientemente entre widgets descendentes sen ter que pasar explicitamente propiedades por construtor. O máis potente é que, se os datos do InheritedWidget cambian, todos os widgets que dependen deses datos son automaticamente reconstruídos.

📌 Características: #

  • Permite que widgets fillos accedan a datos do pai sen ter que pasalos por construtores.
  • É eficiente: só se reconstruen os widgets que usan os datos herdados.
  • É a base de solucións como Provider, Theme, MediaQuery, etc.

📌 Concepto clave: #

  • Provedor de Datos: Un InheritedWidget actúa como un provedor de datos. Colócase alto na árbore de widgets.
  • Acceso aos Datos: Os widgets descendentes poden acceder aos datos usando context.dependOnInheritedWidgetOfExactType<OTeuInheritedWidget>().
  • Reconstrución Automática: Cando os datos no InheritedWidget cambian (e se updateShouldNotify retorna true), calquera widget que chamase a dependOnInheritedWidgetOfExactType será reconstruído.

InheritedWidget en si mesmo é de baixo nivel e, na práctica, raramente o implementas directamente. Con todo, é a base de moitas solucións de xestión de estado populares en Flutter, como Provider (que é o máis recomendado para a xestión de estado básica e media) e Bloc/Riverpod. Entender o seu concepto é crucial para entender como funcionan eses paquetes.

🧪 Exemplo conceptual (sen código detallado): #

// Pódese acceder ao estado global coma este:
final contador = ContadorHeredado.of(contexto).valor;

⚠️ Importante: O uso directo de InheritedWidget é pouco común nos proxectos modernos, xa que se prefire usar librarías como Provider que o encapsulan de forma máis sinxela.

🧪 Exemplo (conceptual, InheritedWidget completo é máis complexo de implementar dende cero): #

Neste exemplo, o ProvedorDeContador é o InheritedWidget que contén o estado contador e a función incrementarContador. Calquera descendente de ProvedorDeContador pode acceder a eles sen que o pai necesite pasalos directamente. Cando _incrementar é chamado no _PaginaConProvedorState, setState reconstrúe o ProvedorDeContador cos novos valores, e updateShouldNotify fai que MostrarContador se actualice.

🔗 Ver o código en DartPad

📚 Fontes de información #