Flutter Riverpod v1.0下StateNotifier监听List类型状态不更新问题
Riverpod 1.0 List类型状态不更新解决方法
根本原因
Riverpod 1.0 采用基于不可变值的状态比对逻辑,你之前直接修改List内部元素的属性,再执行state = state时,本质是同一个List对象的引用赋值,Riverpod检测不到值变化,因此不会触发状态更新。0.4x版本的状态检测逻辑更宽松,所以旧写法可以生效。
你当前的Freezed用法也存在错误:Freezed是用来生成不可变数据模型的工具,不需要绑定到StateNotifier类上,应该作用于你的CoverAlignment数据模型类。
正确实现步骤
1. 改造CoverAlignment为不可变Freezed模型
给CoverAlignment加上Freezed注解,自动生成copyWith方法,用来快速生成修改后的新实例:
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:flutter/foundation.dart'; part 'cover_alignment.freezed.dart'; @freezed class CoverAlignment with _$CoverAlignment { const factory CoverAlignment({ required bool removeSpeechPadding, required double speechBalloonOpacity, required double x, required double y, required Curve curve, required double seconds, required int degrees, // 补充你的其他原有属性 }) = _CoverAlignment; // 你的原有静态方法可以放在这里 static double randomDouble() => /* 原有实现 */; static Curve getCurve() => /* 原有实现 */; static double randomSeconds() => /* 原有实现 */; static int randomIntInRangeWithMinimum({required int min, required int max}) => /* 原有实现 */; }
2. 改造StateNotifier的状态修改逻辑
所有对状态的修改都必须生成全新的List实例,不能直接修改原state的内部元素:
final animateCoversStateNotifierProvider = StateNotifierProvider.autoDispose< AnimateCoversStateNotifier, List<CoverAlignment>>((ref) => AnimateCoversStateNotifier()); class AnimateCoversStateNotifier extends StateNotifier<List<CoverAlignment>> { AnimateCoversStateNotifier() : super([]); void addCover({ required CoverAlignment alignment, }) { // 基于原有state生成新List,添加元素后赋值给state state = [...state, alignment]; } void addCoverAt({ required int index, required CoverAlignment alignment, }) { final newState = List<CoverAlignment>.from(state); newState.insert(index, alignment); state = newState; } void move({ required int cover, bool? readyToOpen, bool? speechBalloonVisible, Duration? animatedOpacityDuration, bool? removeSpeechBalloonPadding, }) { debugPrint('move cover called'); Future.delayed(const Duration(milliseconds: 200), () { if (!mounted) return; // 生成原List的深拷贝 final newState = List<CoverAlignment>.from(state); // 用copyWith生成修改后的新元素,替换原位置的元素 newState[cover] = newState[cover].copyWith( removeSpeechPadding: speechBalloonVisible != true, speechBalloonOpacity: speechBalloonVisible == true ? kMaxSpeechBalloonOpacity : 0.0, x: CoverAlignment.randomDouble(), y: CoverAlignment.randomDouble(), curve: CoverAlignment.getCurve(), seconds: CoverAlignment.randomSeconds(), degrees: CoverAlignment.randomIntInRangeWithMinimum(min: 0, max: 45), ); // 新List赋值给state,触发更新 state = newState; }); } }
注意事项
- 所有List的增删改操作都不能直接操作原state对象,必须生成新的List实例
- 不能直接修改数据模型的属性,必须用
copyWith生成新的模型实例替换旧实例 - 页面端的watch监听逻辑不需要修改,状态更新后会自动触发重建
内容的提问来源于stack exchange,提问作者Zelf
相关产品推荐
相关产品推荐

