1. Flutter Hooks 的简单性
每个 Flutter 开发人员都是从使用 StatefulWidget 开始的,而我们必须通过它的基础。但想象一下,你必须创建一个大型项目,"StatefulWidget"的重用变得痛苦。这就是 flutter hooks 的由来,flutter hooks 通过创建 hooks 帮助 flutter 开发人员重用代码,然后,我们可以快速推进项目,这里有一些示例。
这个类,我们都为"StatefulWidget"创建,但大多数时候,我们从不使用它,通过 flutter hooks,一个小部件的所有状态都在一个类中处理,其性能与"StatefulWidget"相同。
在许多控制器的 StatefulWidget 中,例如 AnimationController
或 TextEditingController
, 我们需要处理所有生命周期方法:initialization, dispose, didUpdateWidget, 甚至在 State 类中添加 TickerProviderStateMixin
,以及在每个需要使用这些控制器的 StatefulWidget 中添加该 mixin。
在 flutter hooks 中,我们只需要创建一个处理控制器生命周期的钩子,然后我们将在每个 HookWidget 中重用相同的钩子。
StatefulWidget 中的动画控制器
HookWidget 中的动画控制器
现在,我们知道使用 flutter hooks 进行编码是多么容易,以及它对于特别大的项目有何用处。我不会在创建少于 10 个小部件的应用程序中使用它,但在需要创建更多小部件的应用程序中,我不会错过使用 flutter hooks。
2. Hooks Riverpod
状态管理的简单重要性是在所有应用程序或多个小部件之间共享一个或多个变量,并且每个变量更改都必须触发正在侦听该变量的小部件中的重建。
如果您尝试仅创建一个全局变量并更改它,则不会触发小部件中的重建。为了解决这个问题,Riverpod 提供了创建一个全局提供程序的可能性,该提供程序主要携带变量,但该提供程序可以携带stream, future, ChangeNotifier,...
可以在应用程序的每个小部件中轻松访问提供者,我们只需将MyApp()
小部件包装到ProviderScrope
中。
在新版本的 hooks_riverpod
中,有一个名为 HookConsumerWidget
的新小部件,我们必须在项目小部件中扩展它。 HookConsumerWidget
在构建中附带了其他参数,即 WidgetRef
(注意 ref
很短),ref
使我们能够读取和观察提供者。
-
读取provider:一次性读取值,值变化时不触发重建。
-
监视provider:每次更改都会触发小部件或正在侦听
provider
的小部件部分的重建。 -
在应用程序中观看相同的 firebase stream
正如我们可以在所有应用程序中查看 provider
一样,我们也可以更改 provider
。
设置flutter_hooks和hooks_riverpod就是这么简单。还有复杂的概念和多种方法来完成同一件事,但应用程序中的大多数状态管理,您可能只会使用这些概念。
3. 一个示例
dart
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
void main() {
runApp(
/// [MyApp] is wrapped in a [ProviderScope].
/// This widget is where the state of most of our providers will be stored.
/// This replaces `MultiProvider` if you've used `provider` before.
const ProviderScope(
child: MyApp(),
),
);
}
/// A provider that creates and listen to a [StateNotifier].
///
/// Providers are declared as global variables.
/// This does not hinder testability, as the state of a provider is instead
/// stored inside a [ProviderScope].
final counterProvider = StateNotifierProvider<Counter, int>((_) => Counter());
/// A simple [StateNotifier] that implements a counter.
///
/// It doesn't have to be a [StateNotifier], and could be anything else such as:
/// - [ChangeNotifier], with [ChangeNotifierProvider]
/// - [Stream], with [StreamProvider]
/// ...
class Counter extends StateNotifier<int> {
Counter() : super(0);
void increment() => state++;
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends HookConsumerWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(
title: const Text('Riverpod counter example'),
),
body: Center(
// HookConsumer is a builder widget that allows you to read providers and utilise hooks.
child: HookConsumer(
builder: (context, ref, _) {
final count = ref.watch(counterProvider);
return Text(
'$count',
style: Theme.of(context).textTheme.headlineMedium,
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider.notifier).increment(),
child: const Icon(Icons.add),
),
);
}
}
Riverpod: riverpod.dev/docs/gettin...
hooks_riverpod:pub.dev/packages/ho...