Flutter Riverpod:Notifier Provider状态初始化问题求助
问题:Riverpod Notifier Provider调用方法时触发null错误
我使用以下Riverpod Notifier Provider代码:
@riverpod class MainProductNew extends _$MainProductNew { @override AsyncValue<MainProductStateModel> build(String id) { return const AsyncValue.loading(); } Future<void> getMainProduct() async { final result = await ref.watch(productViewNewRepositoryProvider).getMainProduct(id); state = AsyncValue.data(state.value!.copyWith(mainProductModel: result.extractDataOrThrow)); } }
调用getMainProduct方法更新状态时触发错误:
Error: Unexpected null value.
错误出现在state.value!.copyWith处,MainProductStateModel是Freezed类,请问如何正确初始化状态?是否需要先创建对象再使用copyWith?
解决方案
问题根源很明确:你的Notifier初始状态是AsyncValue.loading(),这时候state.value是null,用!强制解包自然会抛出空值错误。针对这个问题,有两种靠谱的解决思路:
思路1:初始化时提供默认的状态实例
既然要用copyWith,那初始状态就得是一个有效的MainProductStateModel实例,而不是loading状态。修改build方法,用AsyncValue.data包裹一个默认的空实例(Freezed类通常可以通过工厂方法创建空对象,比如MainProductStateModel.empty(),具体命名看你的Freezed配置):
@override AsyncValue<MainProductStateModel> build(String id) { // 用默认空实例初始化状态 return AsyncValue.data(MainProductStateModel.empty()); }
这样初始状态的state.value就有了有效值,后续调用getMainProduct时,state.value!.copyWith就能安全执行,不会再触发空值错误。
思路2:直接基于接口返回值创建新状态
如果你的业务场景是第一次加载数据时不需要依赖初始状态,那完全可以跳过copyWith,直接用接口返回的数据创建新的MainProductStateModel实例:
Future<void> getMainProduct() async { final result = await ref.watch(productViewNewRepositoryProvider).getMainProduct(id); // 直接用接口数据生成新状态,无需依赖旧state.value state = AsyncValue.data( MainProductStateModel(mainProductModel: result.extractDataOrThrow) ); }
如果后续有刷新需求,需要保留旧状态的其他字段,那可以加个空值判断:
Future<void> getMainProduct() async { final result = await ref.watch(productViewNewRepositoryProvider).getMainProduct(id); final newMainProduct = result.extractDataOrThrow; state = AsyncValue.data( state.value?.copyWith(mainProductModel: newMainProduct) ?? MainProductStateModel(mainProductModel: newMainProduct) ); }
这样不管初始状态有没有值,都能安全更新状态。
内容的提问来源于stack exchange,提问作者Cyrus the Great
相关产品推荐
相关产品推荐

