RiverPod 使用记录
一直被riverpod洗脑,最后投降了。完整的学习了下,然后在项目中实战了。整体来说好用,比provider方便,也解决之前一直的困扰(监听值变化来执行事件)。
1. widget替换
StatelessWidget
替换为ConsumerWidget
。StatefulWidget
和State
替换为ConsumerStatefulWidget
和ConsumerState
。Consumer
可以直接在widget tree中使用。
2. ref的方法 (ref就是ProviderElementBase
)
ref.watch
获取一个provider的值并监听变化,等值变化时重建widget。ref.listen
添加一个监听到provider上,当值变化的时候执行一个动作,如打开一个新页面或展示一个新内容。(事件触发用listen)ref.read
获取一个provider的值并忽略值的改变。如在点击事件中获取一个provider的值。
注意点
1. ref.watch
- 多个provider联用,可以在provider通过ref.watch其他的provider来做到自动更新。
- 不应该在async异步中调用,比如在button的onPresssed中。
- 不应该在initState或其他state生命周期中调用。
2. ref.listen
- 传入2个参数ref和(pre, new)回调函数。可在回调函数中进行操作。
- 可在一个provider或build中。
- 不应该在async异步中调用,比如在button的onPresssed中。
- 不应该在initState或其他state生命周期中调用。
3. ref.read
- 获取数据。通常在用户交互中使用。
- 尽量避免使用ref.read,因为他不是反应式的。(即数据变化的时候,不会跟随的变化)
- 不要在build中使用。
4. ref.refresh
- 使之前的provider失效,然后重新获取数据。 (不是立刻重新获取数据,而是等下一次读取时刷新)
- 重新获取数据不需要返回值时,可使用invalidate.
final productsProvider = FutureProvider((ref) async {
final response = await httpClient.get('https://host.com/products');
return Products.fromJson(response.data);
});
class Example extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final Products products = ref.watch(productsProvider);
return RefreshIndicator(
onRefresh: () => ref.refresh(productsProvider.future),
child: ListView(
children: [
for (final product in products.items) ProductItem(product: product),
],
),
);
}
}
4. ref.invalidate
使provider失效,可以调用很多次,只刷新一次provider。
需要返回state时,使用refresh方法。
3. 使用notifier进行值的更改
使用ref.read
和ref.watch
都可以实现。
final counterProvider = StateProvider((ref) => 0);
Widget build(BuildContext context, WidgetRef ref) {
StateController<int> counter = ref.watch(counterProvider.notifier);
return ElevatedButton(
onPressed: () => counter.state++,
child: const Text('button'),
);
}
简单修改
ref.read(pageIndexProvider.notifier).update((state)=>state-1);
4. 监听哪个值
根据不同的需求,可以监听不同的值。如StreamProvider的使用:final userProvider=StreamProvider<User>(...);
AsyncValue<User>user=ref.watch(userProvider);
监听本身Stream<User>user=ref.watch(userProvider.stream);
监听streamFuture<User>user=ref.watch(userProvider.future);
监听future
5. select
可在ref.watch和ref.listen中使用。
Widget build(BuildContext context, WidgetRef ref) {
String name = ref.watch(userProvider.select((user) => user.name));
return Text(name);
}
监听某一个值,从而减少build次数。
6. 组合provider
provider通过watch另一个provider进行操作。final cityProvider = Provider((ref) => 'London');
监听cityProvider进行获取数据
final weatherProvider = FutureProvider((ref) async {
final city = ref.watch(cityProvider);
return fetchWeather(city: city);
});
7. family
传入一个额外的参数来创建state。
final messagesFamily = FutureProvider.family<Message, String>((ref, id) async {
return dio.get('http://my_api.dev/messages/$id');
});
使用
Widget build(BuildContext context, WidgetRef ref) {
final response = ref.watch(messagesFamily('id'));
}
8. autoDispose
Provider不使用时则销毁,解决内存泄露问题。
9. Provider
- 缓存计算结果。
- 减少重建次数。
- StateNotifierProvider 包装StateNotifier并暴漏state,可通过watch进行观察。
- FutureProvider 参数变化会自动重新获取数据,并一直拥有最新的数据。
- StreamProvider 同FutureProvider,可监听流。
- StateProvider state可以为(1)枚举(2)字符串(3)布尔值(4)数值。 其他复杂的就是用StateNotifierProvider.
- ChangeNotifierProvider (不推荐使用)
9.1 StateNotifierProvider
用法和stateProvider一样,用于比较复杂的State。
final StateNotifierProvider<Counter, int> stateNotifierProvider = StateNotifierProvider<Counter, int>((_) => Counter());
class Counter extends StateNotifier<int> {
Counter() : super(0);
void increment() => state++;
void decrement() => state--;
@override
String toString() {
return 'state:$state';
}
}
9.2 ChangeNotifierProvider
ChangeNotifier和StateNotifier的区别是,需要自己调用notifyListeners通知变更。
final ChangeNotifierProvider<Counter> _counterProvider = ChangeNotifierProvider((_) => Counter());
class Counter extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
void decrement() {
_count--;
notifyListeners();
}
}
class ChangeProviderNotifierExample extends ConsumerWidget {
const ChangeProviderNotifierExample({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(
title: const Text('ChangeNotifierProvider Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Consumer(
builder: (context, watch, _) {
int count = watch.watch(_counterProvider).count;
return Text(
'$count',
style: Theme.of(context).textTheme.headline4,
);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
/// 使用read获取counterProvider。
onPressed: () => ref.read(_counterProvider).increment(),
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
10. ProviderObserver
监听一个ProviderContainer的变化。
- didAddProvider:在每次初始化一个Provider时被调用
- didDisposeProvider:在每次销毁Provider的时候被调用
- didUpdateProvider:每次在Provider更新时都会被调用
内容来自官网或其他地方(看的文章太多忘记地址了),侵删。
转载自:https://juejin.cn/post/7172482155812454431