我目前正在使用 Riverpod 开发 Flutter 应用程序,并且遇到了我不明白的状态管理问题。为了进行调试,我将代码简化为这个示例,您可以运行该示例来跟进。
这是简化的代码,如果您了解 Riverpod 代码生成,您可以运行它:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'main.g.dart';
@riverpod
class RandomNumber extends _$RandomNumber {
@override
String build() {
print('im in build in quote provider');
return Random().nextInt(5).toString();
}
}
final giveBoolProvider = StateProvider<bool>((ref) => false);
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final num = ref.watch(randomNumberProvider); // comment this
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Example')),
body: Center(
child: ElevatedButton(
onPressed: () {
ref.read(giveBoolProvider.notifier).update((state) {
return !state;
});
},
child: ref.watch(giveBoolProvider) == true
? Column(
mainAxisSize: MainAxisSize.min,
children: [Text(num), Text(num)], // comment this
// children: [Text(ref.watch(randomNumberProvider)), Text(ref.watch(randomNumberProvider))], // uncomment this
)
: const Text('giveBool is false'),
),
),
));
}
}
问题: 当我按下按钮时,会显示一个随机数。如果我再次按下按钮,什么也不会发生。第三次按下按钮会显示相同的随机数,因为
randomNumberProvider
的状态没有改变。这是预期的行为。
但是,当我: 注释掉标有
// comment this.
的行
取消注释标有
// uncomment this.
的行
每次都会调用
randomNumberProvider
的构建方法,即使我没有显式更改其状态。这会导致每次按下按钮时都会生成一个新的随机数。
在这两种情况下,都会调用小部件的构建方法。我不确定为什么国家在这两种情况下表现不同。
有人可以解释一下我在这里缺少什么以及为什么这两种情况之间的行为存在差异吗?
谢谢!
随机数提供程序是一个自动处置提供程序,因为它是生成的提供程序的默认配置。
在第一个场景中,每次构建时都会调用
ref.watch
,因此提供程序永远不会被销毁,因为它仍在侦听,从而导致其数据被缓存。
在第二种情况下,根据
ref.watch
公开的值有条件地使用giveBoolProvider
,这会导致每当giveBoolProvider
公开false
时随机数提供程序都会被销毁。下次 giveBoolProvider
暴露 true
时,随机数提供者上的 ref.watch
将再次被调用,因此提供者执行其构建方法并生成一个新数字。