Provider:监听还是读取
本课属于 Coddy Flutter 学习旅程的“状态管理”单元。第 11 课,共 27 课。
从 Provider 获取模型有两种方式,它们的作用不同。
context.watch<StepCounter>() 会获取模型并订阅它:当模型调用 notifyListeners() 时,这个组件会再次构建。在 build 中使用它,适用于屏幕上显示的内容。
context.read<StepCounter>() 只获取一次模型,不会订阅它。在 onPressed 等回调中使用它,这些地方需要调用方法,而不需要显示任何内容:
Widget build(BuildContext context) {
final steps = context.watch<StepCounter>().steps; // 显示
return ElevatedButton(
onPressed: () => context.read<StepCounter>().walk(), // 执行操作
child: Text('$steps steps'),
);
}混用这两种方式,结果一目了然。在 build 中使用 read,会让第一个值一直显示不变。在 onPressed 中使用 watch 会出错,因为点击操作不是构建过程,也没有可供订阅的对象。
挑战
简单Walk 会给模型增加 1000 步,但屏幕上仍显示 0 steps。
- 让步数文本跟随模型更新,这样每次点击都会显示新数字。
- 保持按钮的调用不变。
亲手试试
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class StepCounter extends ChangeNotifier {
int _steps = 0;
int get steps => _steps;
void walk() {
_steps += 1000;
notifyListeners();
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => StepCounter(),
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
final steps = context.read<StepCounter>().steps;
return Scaffold(
appBar: AppBar(title: const Text('Steps')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('$steps steps', style: const TextStyle(fontSize: 40)),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
context.read<StepCounter>().walk();
},
child: const Text('Walk'),
),
],
),
),
);
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
状态管理中的所有课
3Provider
Provider:共享一个模型调用 notifyListenersProvider:监听还是读取Provider:Consumer两个屏幕,一个模型模型中的对象列表多个模型:MultiProvider自己练习: Flutter 在线编译器