riverpod 2.2.0 升级 2.3.6 指南

586 阅读2分钟

目前项目中的 riverpod 固定版本为:riverpod: 2.2.0,最新版为:riverpod: 2.3.6,期间的更新日志可以点击查看

坑点

升级到 2.3.4 的时候,第一次使用 autoDispose 类型的 provider 是没问题的,但是,后续继续使用,就会报错:

 [, , 0]:split-0 error: Bad state: Trying to read an uninitialized value., trace: 
#0      ProxyElementValueNotifier.value (package:riverpod/src/listenable.dart:26:7)
#1      ProviderElementProxy.read (package:riverpod/src/framework/proxy_provider_listenable.dart:117:28)
#2      ProviderContainer.read (package:riverpod/src/framework/container.dart:229:21)
#3      ConsumerStatefulElement.read (package:flutter_riverpod/src/consumer.dart:613:59)
#4      _FeelingDisplayWidgetState.initState (package:×××/src/ui/widget/×××_widget.dart:35:12)
#5      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5219:55)
#6      ComponentElement.mount (package:flutter/src/widgets/framework.dart:5062:5)
#7      Element.inflateWidget (package:flutter/src/widgets/framework.dart:3971:16)
#8      Element.updateChild (package:flutter/src/widgets/framework.dart:3708:18)
#9      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#10     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#11     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:5068:5)
#12     ComponentElement.mount (package:flutter/src/widgets/framework.dart:5062:5)
#13     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3971:16)
#14     MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6570:36)
#15     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6582:32)
#16     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3971:16)
#17     Element.updateChild (package:flutter/src/widgets/framework.dart:3708:18)
#18     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#19     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#20     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:5068:5)
#21     ComponentElement.mount (package:flutter/src/widgets/framework.dart:5062:5)
#22     Element.infl

该 bug 并没有在 2.3.5 中解决,而是在 2.3.6 中解决:

该笔提交记录

1689748126097.jpg

所以,在使用 riverpod 的使用,需要绕过 2.3.42.3.5.

新特性

新增 StreamNotifier + StreamNotifierProvider

在以往使用 StreamProvider 来生成数据,容易使得该 provider 的数据生成方式固定了。

例子🌰:

final configProvider = StreamProvider<int>((ref) => Stream<int>.periodic(const Duration(seconds: ), (value) => value));

监听获取数据(要放到 build() 中,不能放在 initState()

    ref.listen(numProvider, (previous, next) {
      print('previous: ${(previous as AsyncValue<int>).value}  next: ${(next as AsyncValue<int>).value}');
    });

输出结果:

I  previous: null  next: 0
I  previous: 0  next: 1
I  previous: 1  next: 2
I  previous: 2  next: 3
I  previous: 3  next: 4
I  previous: 4  next: 5
...

若使用 StreamNotifier + StreamNotifierProvider 就可以动态更改 stream 的返回值,下面来写个例子:

final numStreamProvider =
    StreamNotifierProvider<NumStreamNotifier, int>(() => NumStreamNotifier());

class NumStreamNotifier extends StreamNotifier<int> {
  @override
  Stream<int> build() {
    return Stream<int>.periodic(const Duration(seconds: 1), (value) => value).take(3);
  }

  refreshNumStream(){
    Stream<int>.periodic(const Duration(seconds: 1), (value){
      return value;
    }).take(5).listen((event) {
      state = AsyncValue.data(event + 100);
    });
  }
}

StreamNotifier 的写法和 StateNotifier 的写法还是有区别的:

  • StreamNotifier 需要重载 build()初始化值,而 StateNotifier 需要在构造方法中初始化。
  • StreamNotifier 的父类 BuildlessStreamNotifier 自带 ref,而 StateNotifier 需要用到 ref 的话,需要自己传进去。

我们五秒后调用下 refreshNumStream()

    Future.delayed(const Duration(seconds: 5), (){
      ref.read(numStreamProvider.notifier).refreshNumStream();
    });

监听输出:

    ref.listen(numStreamProvider, (previous, next) {
      print('previous: ${(previous as AsyncValue<int>).value}  next: ${(next as AsyncValue<int>).value}');
    });

日志:

I  previous: null  next: 0
I  previous: 0  next: 1
I  previous: 1  next: 2
I  previous: 2  next: 100
I  previous: 100  next: 101
I  previous: 101  next: 102
I  previous: 102  next: 103
I  previous: 103  next: 104

写法更新

1

数据源:

final numProvider = StreamProvider<int>((ref) => Stream<int>.periodic(const Duration(seconds: 1), (value) => value));

废弃写法:

ref.watch(numProvider.stream).listen((event) { });

推荐写法:

ref.listen(numProvider, (previous, next) {});

2

废弃写法:

    final numProvider = StreamProvider<int>((ref) => Stream<int>.periodic(const Duration(seconds: 1), (value) => value));
    
    final value = StreamProvider((ref) {
      return ref.watch(numProvider.stream).map((e) => e.toString());
    });

推荐写法:

final numProvider = FutureProvider((ref) => Future(() => 1));

ref.listen(numProvider, (previous, next) {});

总结来说,2.3.x 针对了 StreamProvider 进行了优化,提供新的构建方式和新的写法。