如何向Riverpod Provider传递字符串列表避免无限重建?
解决Riverpod代码生成中传递字符串列表导致Widget重复重建的问题
问题根源在于:每次调用GetUsersProvider([handle])都会创建新的列表实例,Riverpod会将不同的列表实例判定为不同的Provider参数,因此会持续触发Provider重建和Widget刷新,哪怕列表内容完全一致。
以下是几种可行的解决方案:
方案1:自定义不可变列表包装类(手动处理相等性)
创建一个不可变类包裹字符串列表,重写==运算符和hashCode,让内容相同的实例被判定为相等:
@immutable class UserHandles { final List<String> handles; const UserHandles(this.handles); @override bool operator ==(Object other) => identical(this, other) || other is UserHandles && runtimeType == other.runtimeType && const ListEquality().equals(handles, other.handles); @override int get hashCode => const ListEquality().hash(handles); }
修改Provider定义,接收这个包装类作为参数:
@riverpod Future<List<User>> getUsers(GetUsersRef ref, UserHandles handles) async { // 网络请求逻辑,使用handles.handles获取列表 return await api.fetchUsers(handles.handles); }
使用时传入包装类实例:
ref.watch(getUsersProvider(UserHandles([handle])));
方案2:用Freezed生成不可变类(自动处理相等性)
如果项目已经使用freezed,可以快速生成自带相等性判断的类:
import 'package:freezed_annotation/freezed_annotation.dart'; part 'user_handles.freezed.dart'; @freezed class UserHandles with _$UserHandles { const factory UserHandles(List<String> handles) = _UserHandles; }
用法和方案1完全一致,Freezed会自动生成正确的==和hashCode实现。
方案3:在Widget中缓存列表实例
如果不想新增类,可以在Widget内部缓存列表实例,确保内容不变时复用同一个实例:
方式A:StatefulWidget缓存
class UserListWidget extends StatefulWidget { final String handle; const UserListWidget({super.key, required this.handle}); @override State<UserListWidget> createState() => _UserListWidgetState(); } class _UserListWidgetState extends State<UserListWidget> { late List<String> _handles; @override void initState() { super.initState(); _handles = [widget.handle]; } @override void didUpdateWidget(covariant UserListWidget oldWidget) { super.didUpdateWidget(oldWidget); // 仅当handle变化时更新列表实例 if (oldWidget.handle != widget.handle) { _handles = [widget.handle]; } } @override Widget build(BuildContext context) { final users = ref.watch(getUsersProvider(_handles)); // 构建UI逻辑 return ...; } }
方式B:Flutter Hooks缓存(如果使用hooks)
class UserListWidget extends HookConsumerWidget { final String handle; const UserListWidget({super.key, required this.handle}); @override Widget build(BuildContext context, WidgetRef ref) { // 仅当handle变化时重新创建列表 final handles = useMemoized(() => [handle], [handle]); final users = ref.watch(getUsersProvider(handles)); // 构建UI逻辑 return ...; } }
内容的提问来源于stack exchange,提问作者Ajay
相关产品推荐
相关产品推荐

