一直被riverpod洗脑,最后投降了。完整的学习了下,然后在项目中实战了。整体来说好用,比provider方便,也解决之前一直的困扰(监听值变化来执行事件)。
1. widget替换
1.StatelessWidget
替换为ConsumerWidget
。
2.StatefulWidget
和State
替换为ConsumerStatefulWidget
和ConsumerState
。
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.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
- 缓存计算结果。
- 减少重建次数。
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的相关知识,提升工作效率。
有需要的小伙伴,可以点击下方卡片领取,无偿分享