RiverPod 使用记录

本文介绍了RiverPod在项目中的应用,对比了它与Provider的便利性,并详细讲解了ref的各种方法,包括watch、listen、read、refresh和invalidate的使用场景。此外,还探讨了notifier的值更改、选择性监听、provider组合、family参数、autoDispose特性以及不同类型的Provider,如StateNotifierProvider和ChangeNotifierProvider。最后提到了ProviderObserver的监听功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一直被riverpod洗脑,最后投降了。完整的学习了下,然后在项目中实战了。整体来说好用,比provider方便,也解决之前一直的困扰(监听值变化来执行事件)。

1. widget替换

1.StatelessWidget替换为ConsumerWidget
2.StatefulWidgetState替换为ConsumerStatefulWidgetConsumerState
3.Consumer可以直接在widget tree中使用。

2. ref的方法 (ref就是ProviderElementBase)

1.ref.watch 获取一个provider的值并监听变化,等值变化时重建widget。
2.ref.listen 添加一个监听到provider上,当值变化的时候执行一个动作,如打开一个新页面或展示一个新内容。(事件触发用listen)
3.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 {@overrideWidget 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.readref.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);监听stream
  • Future<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

  • 缓存计算结果。
  • 减少重建次数。

1.StateNotifierProvider 包装StateNotifier并暴漏state,可通过watch进行观察。
2.FutureProvider 参数变化会自动重新获取数据,并一直拥有最新的数据。
3.StreamProvider 同FutureProvider,可监听流。
4.StateProvider state可以为(1)枚举(2)字符串(3)布尔值(4)数值。 其他复杂的就是用StateNotifierProvider.
5.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--;@overrideString 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});@overrideWidget 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更新时都会被调用

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值