You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何向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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 21:52:21