Cómo gestionar el estado en Flutter con Provider

Introducción
La gestión del estado implica el seguimiento de los cambios de estado en toda la aplicación.
El provider
paquete es una solución para las necesidades de gestión estatal.
En este artículo, aprenderá cómo aplicar provider
una aplicación Flutter de muestra para administrar el estado de la información de la cuenta de usuario.
Prerrequisitos
Para completar este tutorial, necesitarás:
- Para descargar e instalar Flutter .
- Para descargar e instalar Android Studio o Visual Studio Code .
- Se recomienda instalar complementos para su editor de código:
Flutter
yDart
complementos instalados para Android Studio.Flutter
extensión instalada para Visual Studio Code.
- La familiaridad con la navegación y las rutas será beneficiosa, pero no obligatoria.
- La familiaridad con el estado del formulario también será beneficiosa, pero no es obligatoria.
Este tutorial fue verificado con Flutter v2.0.6, Android SDK v31.0.2 y Android Studio v4.1.
Entendiendo el problema
Imagina una situación en la que quieres crear una aplicación que personaliza algunas de sus pantallas con algunos datos del usuario, como su nombre. Los métodos normales para pasar datos entre pantallas se convertirían rápidamente en un lío de devoluciones de llamadas, datos no utilizados y widgets reconstruidos innecesariamente. Con una biblioteca de interfaz como React, este es un problema común llamado prop boring .
Si quisiéramos pasar datos desde cualquiera de esos widgets, entonces tendríamos que aumentar aún más cada widget intermedio con más devoluciones de llamadas sin usar. Para la mayoría de las funciones pequeñas, esto puede hacer que no valga la pena el esfuerzo.
Afortunadamente para nosotros, el provider
paquete nos permite almacenar nuestros datos en un widget que está más arriba, como donde sea que inicialicemos nuestro MaterialApp
, luego acceder a él y cambiarlo directamente desde los sub-widgets, independientemente de la anidación y sin reconstruir todo lo demás.
Paso 1: Configuración del proyecto
Una vez que haya configurado su entorno para Flutter, puede ejecutar lo siguiente para crear una nueva aplicación:
- flutter create flutter_provider_example
Navegue hasta el nuevo directorio del proyecto:
- cd flutter_provider_example
El uso flutter create
producirá una aplicación de demostración que mostrará la cantidad de veces que se hace clic en un botón.
Paso 2: Agregar el providercomplemento
A continuación, necesitaremos agregar el provider
complemento dentro de nuestro pubspec.yaml
:
archivo pubspec.yaml
dependencies: flutter: sdk: flutter provider: ^3.1.0
Luego, guarde los cambios en su archivo.
Nota: Si está utilizando VS Code, puede considerar usar la extensión Pubspec Assist para agregar dependencias rápidamente.
Ahora podemos continuar y ejecutar esto en el simulador o dispositivo iOS o Android de su elección.
Paso 3: Andamiaje del proyecto
Necesitaremos dos pantallas, nuestro enrutador y una barra de navegación. Estamos configurando una página para mostrar los datos de nuestra cuenta y otra para actualizarla con el estado que se almacena, cambia y transmite desde nuestro enrutador.
Abra main.dart
su editor de código y modifique las siguientes líneas de código:
lib/main.dart
import 'package:flutter/material.dart';import 'package:provider/provider.dart';import './screens/account.dart';import './screens/settings.dart';void main() { runApp(MyApp());}class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Provider Demo', home: MyHomePage(), ); }}class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() = _MyHomePageState();}class _MyHomePageState extends StateMyHomePage { @override Widget build(BuildContext context) { return MaterialApp(home: AccountScreen(), routes: { 'account_screen': (context) = AccountScreen(), 'settings_screen': (context) = SettingsScreen(), }); }}
Crea un navbar.dart
archivo y ábrelo con tu editor de código:
lib/navbar.dart
import 'package:flutter/material.dart';import './screens/account.dart';import './screens/settings.dart';class Navbar extends StatelessWidget { @override Widget build(BuildContext context) { return Container( color: Colors.blue, child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: Widget[ TextButton( onPressed: () = Navigator.pushReplacementNamed(context, AccountScreen.id), child: Icon(Icons.account_circle, color: Colors.white) ), TextButton( onPressed: () = Navigator.pushReplacementNamed(context, SettingsScreen.id), child: Icon(Icons.settings, color: Colors.white) ), ], ), ); }}
En el lib
directorio, crea un nuevo screens
subdirectorio:
- mkdir lib/screens
En este subdirectorio, crea un settings.dart
archivo. Este se utilizará para crear el estado de nuestro formulario, configurar un mapa para almacenar nuestras entradas y agregar un botón de envío que utilizaremos más adelante:
lib/pantallas/configuraciones.dart
import 'package:flutter/material.dart';import 'package:provider/provider.dart';import '../main.dart';import '../navbar.dart';class SettingsScreen extends StatelessWidget { static const String id = 'settings_screen'; final formKey = GlobalKeyFormState(); final Map data = {'name': String, 'email': String, 'age': int}; @override Widget build(BuildContext context) { return Scaffold( bottomNavigationBar: Navbar(), appBar: AppBar(title: Text('Change Account Details')), body: Center( child: Container( padding: EdgeInsets.symmetric(vertical: 20, horizontal: 30), child: Form( key: formKey, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: Widget[ TextFormField( decoration: InputDecoration(labelText: 'Name'), onSaved: (input) = data['name'] = input, ), TextFormField( decoration: InputDecoration(labelText: 'Email'), onSaved: (input) = data['email'] = input, ), TextFormField( decoration: InputDecoration(labelText: 'Age'), onSaved: (input) = data['age'] = input, ), TextButton( onPressed: () = formKey.currentState.save(), child: Text('Submit'), style: TextButton.styleFrom( primary: Colors.white, backgroundColor: Colors.blue, ), ) ] ), ), ), ), ); }}
También en este subdirectorio, crea un account.dart
archivo que se utilizará para mostrar la información de la cuenta:
lib/pantallas/cuenta.dart
import 'package:flutter/material.dart';import 'package:provider/provider.dart';import '../main.dart';import '../navbar.dart';class AccountScreen extends StatelessWidget { static const String id = 'account_screen'; @override Widget build(BuildContext context) { return Scaffold( bottomNavigationBar: Navbar(), appBar: AppBar( title: Text('Account Details'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: Widget[ Text('Name: '), Text('Email: '), Text('Age: '), ], ), ), ); }}
Compila tu código y ejecútalo en un emulador:
En este punto, tienes una aplicación con una pantalla de Cuenta y una pantalla de Configuración.
Paso 4 — UsoProvider
Para configurar un testamento provider
será necesario envolver nuestro MaterialApp
en un Provider
con el tipo de nuestros datos.
Vuelve a consultarlo main.dart
y ábrelo en tu editor de código. Para este tutorial, el tipo de datos es Map
. Por último, debemos configurarlo create
para que luego usemos nuestro context
y data
:
lib/main.dart
// ...class _MyHomePageState extends StateMyHomePage { Map data = { 'name': 'Sammy Shark', 'email': 'example@example.com', 'age': 42 }; @override Widget build(BuildContext context) { return ProviderMap( create: (context) = data, child: MaterialApp(home: AccountScreen(), routes: { 'account_screen': (context) = AccountScreen(), 'settings_screen': (context) = SettingsScreen(), }), ); }}
El data
mapa ahora está disponible en todas las demás pantallas y widgets que main.dart
llaman e importan el provider
paquete.
Todo lo que le pasamos a nuestro Provider
creador ahora está disponible en Provider.ofMap(context)
. Tenga en cuenta que el tipo que pasa debe coincidir con el tipo de datos que nuestro creador Provider
espera.
Nota: Si estás usando VS Code, quizás quieras considerar usar fragmentos , ya que probablemente accederás provider
a mucho:
dardo.json
"Provider": { "prefix": "provider", "body": [ "Provider.of$1(context).$2" ]}
Vuelve a consultarlo account.dart
y ábrelo en tu editor de código. Agrega las siguientes líneas de código:
lib/pantallas/cuenta.dart
// ...body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: Widget[ Text('Name: ' + Provider.ofMap(context)['name'].toString()), Text('Email: ' + Provider.ofMap(context)['email'].toString()), Text('Age: ' + Provider.ofMap(context)['age'].toString()), ]), ),)// ...
Compila tu código y ejecútalo en un emulador:
En este punto, tienes una aplicación con datos de usuario codificados que se muestran en la pantalla Cuenta.
Paso 5 — UsoChangeNotifier
Usar Provider
este método parece muy descendente, ¿qué pasa si queremos pasar datos y modificar nuestro mapa? El método Provider
por sí solo no es suficiente para eso. Primero, necesitamos descomponer nuestros datos en su propia clase que extienda ChangeNotifier
. Provider
no funcionará con eso, por lo que necesitamos cambiarlo a ChangeNotifierProvider
y pasar una instancia de nuestra Data
clase en su lugar.
Ahora estamos pasando una clase completa y no solo una única variable, esto significa que podemos comenzar a crear métodos que pueden manipular nuestros datos, que también estarán disponibles para todo lo que acceda Provider
.
Después de cambiar cualquiera de nuestros datos globales que queramos usar notifyListeners
, esto reconstruirá todos los widgets que dependen de él.
Revisalo main.dart
y ábrelo en tu editor de código:
lib/main.dart
// ...class _MyHomePageState extends StateMyHomePage { @override Widget build(BuildContext context) { return ChangeNotifierProviderData( create: (context) = Data(), child: MaterialApp(home: AccountScreen(), routes: { 'account_screen': (context) = AccountScreen(), 'settings_screen': (context) = SettingsScreen(), }), ); }}class Data extends ChangeNotifier { Map data = { 'name': 'Sammy Shark', 'email': 'example@example.com', 'age': 42 }; void updateAccount(input) { data = input; notifyListeners(); }}
Dado que cambiamos nuestro Provider
tipo, necesitamos actualizar nuestras llamadas a él. Vuelve a visitarlo account.dart
y ábrelo en tu editor de código:
lib/pantallas/cuenta.dart
// ...body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: Widget[ Text('Name: ' + Provider.ofData(context).data['name'].toString()), Text('Email: ' + Provider.ofData(context).data['email'].toString()), Text('Age: ' + Provider.ofData(context).data['age'].toString()), ]), ),)// ...
Para pasar datos, necesitaremos acceder al Provider
método que se pasó en la Data
clase. Vuelva a consultarlo settings.dart
y ábralo en su editor de código:
lib/pantallas/configuraciones.dart
TextButton( onPressed: () { formKey.currentState.save(); Provider.ofData(context, listen: false).updateAccount(data); formKey.currentState.reset(); },)
Compila tu código y ejecútalo en un emulador:
En este punto, tienes una aplicación que admite la actualización de la información del usuario en la pantalla de Configuración y la visualización de los cambios en la pantalla de Cuenta.
Conclusión
En este artículo, aprendió cómo aplicar provider
una aplicación Flutter de muestra para administrar el estado de la información de la cuenta de usuario.
Si desea obtener más información sobre Flutter, consulte nuestra página de temas de Flutter para ver ejercicios y proyectos de programación.
Deja una respuesta