状态管理的概念仍然是Flutter中最关键的话题之一。这是因为我们在Flutter中所做的一切,从接收用户信息的相关操作到显示一个数据,都是在处理状态。因此,以最好的方式管理这些数据,可以确保应用程序的编码干净,抽象得当,运行顺畅,并提供尽可能好的结果。
多年来已经开发了许多状态管理解决方案,每一个都是基于相同的概念,即以最干净和最容易访问的方式操作或修改状态。在这篇文章中,我们将用Flutter最好的状态管理包之一来构建一个示例应用程序。Provider。
在我们开始之前,请注意,本文假设你的机器上有一个可运行的Flutter开发环境,以及Flutter的工作知识。
让我们来谈谈管理Flutter应用程序中的状态意味着什么。
什么是Flutter中的状态?
Flutter中的 "状态 "指的是存储在部件内的数据,可以根据当前的操作进行修改。一个应用程序的状态可以在应用程序开始时,或在页面重新加载时被更新或完全改变。
这意味着小部件所做的一切都需要处理从用户那里获取的数据,并在它们之间传递以执行一个或多个操作。Flutter也可以使用状态来向用户显示信息片段。
什么是提供者?
由Remi Rousselet创建的Provider包,旨在尽可能干净地处理状态。在Provider中,widget会监听状态的变化并在收到通知后立即更新。
因此,当状态发生变化时,不是整个widget树被重建,而是只有受影响的widget被改变,从而减少工作量,使应用程序运行得更快、更流畅。
使用提供者的状态管理
回想一下我们之前讨论的关于Provider的内容:widget会监听变化并在有重建时通知对方。一旦状态发生变化,那个特定的小组件就会重建,而不影响树上的其他小组件。
三个主要的组件使这一切成为可能:Flutter中的ChangeNotifier 类,ChangeNotifierProvider (主要用于我们的示例应用程序),以及Consumer 小部件。
无论从ChangeNotifier 类中观察到的状态有什么变化,都会导致监听小部件的重建。提供者包提供了不同类型的提供者--下面列出了其中的一些。
Provider类接受一个值并将其公开,无论其值的类型如何ListenableProvider是用于可听对象的特定提供者。它将监听,然后要求依赖于它并受状态变化影响的部件在监听器被调用的任何时候进行重建ChangeNotifierProvider与ListenableProvider相似,但用于ChangeNotifier对象,并在需要时自动调用ChangeNotifier.disposeValueListenableProvider侦听一个ValueListenable并公开其值。StreamProvider侦听一个流,公开最新发出的值,并要求依赖于该流的小部件进行重建FutureProvider接受一个Future类,并在未来完成时更新依赖于它的小工具
开始使用
首先创建一个新的项目,并在你的pubspec.yaml 文件中的依赖项块中添加这一行。
dependencies:
provider: ^5.0.0
运行pub get 命令以获得软件包的本地拷贝。
flutter pub get
接下来,我们需要在main.dart 文件中创建一个新的Material应用。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: Text('Material App Bar'),
),
body: Center(
child: Container(
child: Text('Hello World'),
),
),
),
);
}
}
管理状态数据
现在,创建一个新的类,包含应用程序所需的状态数据。让我们把它命名为UserDetailsProvider 。UserDetailsProvider 类将在这里声明所有处理状态的方法。
这个类扩展了ChangeNotifier 类;ChangeNotifier 为我们提供了对notifyListeners 方法的访问,我们将用它来通知监听部件在状态改变时进行重建。
我们为我们的TextFormField 声明两个控制器:name 和age 。基于用户输入更新用户姓名和年龄的方法也在这个类中声明。
所有涉及到应用程序状态的东西都在这里声明。
class UserDetailsProvider extends ChangeNotifier {
TextEditingController nameController = TextEditingController();
TextEditingController ageController = TextEditingController();
int _age = 0;
String _userName = '';
int get userAge => _age;
String get userName => _userName;
void updateAge(int age) {
_age = age;
notifyListeners();
}
void updateName(String name) {
_userName = name;
notifyListeners();
}
}
更新状态
在名字被更新后,我们调用notifyListeners 方法,该方法将状态的改变通知给监听小部件,因此,触发了所有相关小部件的重建。
现在我们有了UserDetailsProvider 类(处理状态),我们需要通过使用ChangeNotifierProvider 将该类链接到屏幕上。现在,在主块的runApp 方法中,用一个ChangeNotifierProvider 来包装整个应用程序。
ChangeNotifierProvider 暴露了两个重要的属性:create 和child 。我们声明的类扩展了ChangeNotifier ,被传递到create 属性中,将该类与屏幕链接起来。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(
ChangeNotifierProvider<UserDetailsProvider>(
create: (_) => UserDetailsProvider(),
child: MyApp(),
),
);
// ignore: use_key_in_widget_constructors
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Material App',
home: HomeScreen(),
);
}
}
现在,应用程序被链接到提供状态的类上;每当状态发生变化时,就会导致应用程序内屏幕的重建。
收集用户数据
目前,HomeScreen widget包含一个带有两个TextFormFields的表单,以接收用户的姓名和年龄。此外,还包括一个RawMaterialButton ,以便在用户传入所需的细节后保存更改。
在这组小组件之后,我们有两个Text 小组件,显示用户给出的数值。这两个小部件是唯一需要在应用状态发生变化时进行更新的小部件。
这意味着我们不需要每次状态发生变化时都要重建每个屏幕。因此,我们需要一种方法来选择性地重建只有与状态变化有关的Text 小部件。为此,我们有Consumer widget。
选择性地更新状态
Consumer 小组件允许只重建子小组件而不影响小组件树中的其他小组件。如前所述,我们希望只有显示用户给出的细节的text widget可以更新。
我们通过用一个Column 来包装两个Text 小部件,并在Consumer 小部件暴露的builder 函数中返回来实现这个目标。
Consumer<UserDetailsProvider>(
builder: (context, provider, child) {
return Column(
children: [
Text(
'Hi ' + provider.userName,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Text(
'You are ' + provider.userAge.toString() + ' years old',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w400,
),
),
],
);
},
),
现在,每当应用程序中的状态发生变化时,只有Text 小部件会更新。
请确保在尽可能低的级别上使用提供者;你只能对受影响的部件使用提供者。在高层次上使用它将导致与状态变化无关的部件重建。Consumer widget也是如此;确保你在特定级别上消费,以避免重建整个widget树。
我们的示例应用程序终于准备好了!
结论
在Flutter中强调状态管理的重要性怎么说都不过分。今天,我们已经剖析了Provider包,并使用它来管理一个Flutter示例应用程序的状态。希望通过本文旁征博引的实践知识,你现在能以一种干净的、更容易理解的方式正确管理你的应用程序的状态。
The postA quick guide to Provider for Flutter state managementappeared first onLogRocket Blog.