La gestió de l'estat és un dels conceptes més importants en el desenvolupament d'aplicacions amb Flutter. L'estat es refereix a qualsevol dada que pot canviar durant el cicle de vida de l'aplicació, com ara el text d'un camp de formulari, la selecció d'un element en una llista o la resposta d'una API.

Objectius d'Aquesta Secció

  • Entendre què és l'estat en Flutter.
  • Conèixer les diferents maneres de gestionar l'estat.
  • Aprendre a utilitzar setState i InheritedWidget per a la gestió bàsica de l'estat.

Què és l'Estat?

L'estat és qualsevol dada que pot canviar durant el cicle de vida de l'aplicació. En Flutter, hi ha dos tipus principals de widgets que gestionen l'estat:

  1. Stateless Widgets: No mantenen cap estat intern. Són immutables i es tornen a construir cada vegada que es criden.
  2. Stateful Widgets: Mantenen un estat intern que pot canviar durant el cicle de vida del widget. Són mutables i poden actualitzar-se dinàmicament.

Maneres de Gestionar l'Estat

Hi ha diverses maneres de gestionar l'estat en Flutter, cadascuna amb els seus avantatges i inconvenients. Les més comunes són:

  1. setState: La manera més bàsica de gestionar l'estat en Flutter. S'utilitza per actualitzar l'estat d'un StatefulWidget.
  2. InheritedWidget: Permet compartir dades entre widgets sense necessitat de passar-les explícitament a través de constructors.
  3. Provider: Un paquet popular per a la gestió de l'estat que es basa en InheritedWidget.
  4. Riverpod: Una alternativa moderna a Provider amb una API més senzilla i funcionalitats avançades.
  5. Bloc (Business Logic Component): Un patró que separa la lògica de negoci de la interfície d'usuari, facilitant la gestió de l'estat en aplicacions complexes.

Utilitzant setState

setState és la manera més bàsica i directa de gestionar l'estat en Flutter. S'utilitza dins d'un StatefulWidget per notificar a Flutter que l'estat ha canviat i que el widget s'ha de reconstruir.

Exemple Pràctic

A continuació, es mostra un exemple senzill d'un StatefulWidget que utilitza setState per actualitzar un comptador:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterScreen(),
    );
  }
}

class CounterScreen extends StatefulWidget {
  @override
  _CounterScreenState createState() => _CounterScreenState();
}

class _CounterScreenState extends State<CounterScreen> {
  int _counter = 0;

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Gestió de l\'Estat amb setState'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Has premut el botó aquest nombre de vegades:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Explicació del Codi

  1. MyApp: És un StatelessWidget que defineix l'aplicació principal.
  2. CounterScreen: És un StatefulWidget que conté l'estat _counter.
  3. _CounterScreenState: La classe d'estat que manté el valor del comptador i defineix el mètode _incrementCounter per actualitzar l'estat.
  4. setState: Quan es crida _incrementCounter, setState notifica a Flutter que l'estat ha canviat, i el widget es reconstrueix amb el nou valor del comptador.

Utilitzant InheritedWidget

InheritedWidget és una manera més avançada de compartir dades entre widgets sense necessitat de passar-les explícitament a través de constructors. És útil quan es necessita compartir dades entre molts widgets en diferents nivells de l'arbre de widgets.

Exemple Pràctic

A continuació, es mostra un exemple senzill d'un InheritedWidget que comparteix un comptador entre diversos widgets:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterProvider(
        counter: 0,
        child: CounterScreen(),
      ),
    );
  }
}

class CounterProvider extends InheritedWidget {
  final int counter;

  CounterProvider({Key? key, required this.counter, required Widget child})
      : super(key: key, child: child);

  @override
  bool updateShouldNotify(CounterProvider oldWidget) {
    return oldWidget.counter != counter;
  }

  static CounterProvider? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<CounterProvider>();
  }
}

class CounterScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counter = CounterProvider.of(context)?.counter ?? 0;

    return Scaffold(
      appBar: AppBar(
        title: Text('Gestió de l\'Estat amb InheritedWidget'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Has premut el botó aquest nombre de vegades:',
            ),
            Text(
              '$counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
    );
  }
}

Explicació del Codi

  1. CounterProvider: És un InheritedWidget que conté l'estat del comptador.
  2. updateShouldNotify: Defineix quan s'ha de notificar als widgets dependents que l'estat ha canviat.
  3. of: Un mètode estàtic que permet als widgets descendents accedir a l'estat del CounterProvider.
  4. CounterScreen: Un StatelessWidget que accedeix a l'estat del comptador a través del CounterProvider.

Exercicis Pràctics

Exercici 1: Incrementar i Decrementar el Comptador

Modifica l'exemple de setState per afegir un botó que decrementi el valor del comptador.

Solució

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterScreen(),
    );
  }
}

class CounterScreen extends StatefulWidget {
  @override
  _CounterScreenState createState() => _CounterScreenState();
}

class _CounterScreenState extends State<CounterScreen> {
  int _counter = 0;

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

  void _decrementCounter() {
    setState(() {
      _counter--;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Gestió de l\'Estat amb setState'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Has premut el botó aquest nombre de vegades:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ),
          SizedBox(height: 10),
          FloatingActionButton(
            onPressed: _decrementCounter,
            tooltip: 'Decrement',
            child: Icon(Icons.remove),
          ),
        ],
      ),
    );
  }
}

Exercici 2: Compartir Estat amb InheritedWidget

Modifica l'exemple de InheritedWidget per permetre incrementar el comptador des de diferents widgets.

Solució

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int _counter = 0;

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

  @override
  Widget build(BuildContext context) {
    return CounterProvider(
      counter: _counter,
      incrementCounter: _incrementCounter,
      child: MaterialApp(
        home: CounterScreen(),
      ),
    );
  }
}

class CounterProvider extends InheritedWidget {
  final int counter;
  final VoidCallback incrementCounter;

  CounterProvider({
    Key? key,
    required this.counter,
    required this.incrementCounter,
    required Widget child,
  }) : super(key: key, child: child);

  @override
  bool updateShouldNotify(CounterProvider oldWidget) {
    return oldWidget.counter != counter;
  }

  static CounterProvider? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<CounterProvider>();
  }
}

class CounterScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counterProvider = CounterProvider.of(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('Gestió de l\'Estat amb InheritedWidget'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Has premut el botó aquest nombre de vegades:',
            ),
            Text(
              '${counterProvider?.counter ?? 0}',
              style: Theme.of(context).textTheme.headline4,
            ),
            ElevatedButton(
              onPressed: counterProvider?.incrementCounter,
              child: Text('Incrementar Comptador'),
            ),
          ],
        ),
      ),
    );
  }
}

Conclusió

En aquesta secció, hem après què és l'estat en Flutter i com gestionar-lo utilitzant setState i InheritedWidget. Hem vist exemples pràctics i hem realitzat exercicis per reforçar els conceptes apresos. En la següent secció, explorarem el paquet Provider per a una gestió de l'estat més avançada i escalable.

Curs de Desenvolupament Flutter

Mòdul 1: Introducció a Flutter

Mòdul 2: Conceptes Bàsics de Programació en Dart

Mòdul 3: Widgets de Flutter

Mòdul 4: Gestió de l'Estat

Mòdul 5: Navegació i Enrutament

Mòdul 6: Xarxes i APIs

Mòdul 7: Persistència i Emmagatzematge

Mòdul 8: Conceptes Avançats de Flutter

Mòdul 9: Proves i Depuració

Mòdul 10: Desplegament i Manteniment

Mòdul 11: Flutter per a Web i Escriptori

© Copyright 2024. Tots els drets reservats