RiverPod 使用记录

image.png

一直被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 {
  @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.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--;
  
 @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 StatelessWidget {
 @override
 Widget build(BuildContext context) {
  return Scaffold(
   appBar: AppBar(
     title: Text('ChangeNotifierProvider Example'),
   ),
​
   body: Center(
     child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
       Text(
        'You have pushed the button this many times:',
       ),
       Consumer(
        builder: (context, watch, _) {
         int count = watch(_counterProvider).count;
         return Text(
          '$count',
          style: Theme.of(context).textTheme.headline4,
         );
        },
       ),
      ],
     ),
   ),
   floatingActionButton: FloatingActionButton(
     /// 使用read获取counterProvider。
     onPressed: () => context.read(_counterProvider).increment(),
     tooltip: 'Increment',
     child: Icon(Icons.add),
   ),
  );
 }
}

10. ProviderObserver

监听一个ProviderContainer的变化。

  • didAddProvider:在每次初始化一个Provider时被调用
  • didDisposeProvider:在每次销毁Provider的时候被调用
  • didUpdateProvider:每次在Provider更新时都会被调用

内容来自官网或其他地方(看的文章太多忘记地址了),侵删。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容