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

如何为Riverpod Provider传递动态初始值

解决Riverpod为多页面实例传递不同初始Filter的问题

要实现每个页面实例拥有独立的Filter状态且能自定义初始值,你需要使用Riverpod的Family Provider——它允许你根据传入的参数创建多个独立的Provider实例,正好适配多页面不同初始配置的场景。

步骤1:定义Filter模型

先创建可修改的Filter类,实现copyWith方法方便后续状态更新,同时确保类能被正确哈希(用于Family区分不同实例):

class Filter {
  final String category;
  final bool isActive;

  Filter({required this.category, required this.isActive});

  // 生成新状态的拷贝方法
  Filter copyWith({String? category, bool? isActive}) {
    return Filter(
      category: category ?? this.category,
      isActive: isActive ?? this.isActive,
    );
  }

  // 必须实现==和hashCode,确保Family能区分不同的初始Filter
  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Filter &&
          runtimeType == other.runtimeType &&
          category == other.category &&
          isActive == other.isActive;

  @override
  int get hashCode => category.hashCode ^ isActive.hashCode;
}

步骤2:创建Family类型的Notifier Provider

使用NotifierProvider.family创建带参数的Provider,Notifier子类通过build方法接收初始Filter参数:

import 'package:flutter_riverpod/flutter_riverpod.dart';

// Family Provider:泛型依次为Notifier类型、状态类型、传入的参数类型
final filterProvider = NotifierProvider.family<FilterNotifier, Filter, Filter>(
  FilterNotifier.new,
);

class FilterNotifier extends FamilyNotifier<Filter, Filter> {
  @override
  Filter build(Filter initialFilter) {
    // 以传入的初始Filter作为状态初始值
    return initialFilter;
  }

  // 自定义修改状态的方法
  void updateCategory(String newCategory) {
    state = state.copyWith(category: newCategory);
  }

  void toggleActiveStatus() {
    state = state.copyWith(isActive: !state.isActive);
  }
}

步骤3:在页面实例中使用不同的初始Filter

每个页面实例传入独有的初始Filter参数,即可获得独立的状态实例:

// 第一个页面实例:初始分类为"Books",激活状态为true
class BooksFilterPage extends ConsumerWidget {
  const BooksFilterPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 传入初始Filter,监听对应的状态
    final currentFilter = ref.watch(filterProvider(
      Filter(category: "Books", isActive: true),
    ));

    return Scaffold(
      appBar: AppBar(title: const Text("书籍筛选")),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            Text("当前分类:${currentFilter.category}"),
            Switch(
              value: currentFilter.isActive,
              onChanged: (_) {
                // 调用Notifier方法修改状态
                ref.read(filterProvider(
                  Filter(category: "Books", isActive: true),
                ).notifier).toggleActiveStatus();
              },
            ),
            ElevatedButton(
              onPressed: () {
                ref.read(filterProvider(
                  Filter(category: "Books", isActive: true),
                ).notifier).updateCategory("科幻小说");
              },
              child: const Text("切换到科幻分类"),
            ),
          ],
        ),
      ),
    );
  }
}

// 第二个页面实例:初始分类为"Electronics",激活状态为false
class ElectronicsFilterPage extends ConsumerWidget {
  const ElectronicsFilterPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final currentFilter = ref.watch(filterProvider(
      Filter(category: "Electronics", isActive: false),
    ));

    return Scaffold(
      appBar: AppBar(title: const Text("电子产品筛选")),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            Text("当前分类:${currentFilter.category}"),
            Switch(
              value: currentFilter.isActive,
              onChanged: (_) {
                ref.read(filterProvider(
                  Filter(category: "Electronics", isActive: false),
                ).notifier).toggleActiveStatus();
              },
            ),
            ElevatedButton(
              onPressed: () {
                ref.read(filterProvider(
                  Filter(category: "Electronics", isActive: false),
                ).notifier).updateCategory("智能手机");
              },
              child: const Text("切换到手机分类"),
            ),
          ],
        ),
      ),
    );
  }
}

为什么之前的方法无效?

普通的NotifierProvider是全局单例,不管在哪个页面调用,都会复用同一个状态实例。直接在build方法传参数,无法让Riverpod区分不同页面的状态需求,而Family Provider会根据传入的初始Filter参数,为每个页面创建独立的状态容器,完美解决多实例独立状态的问题。

内容的提问来源于stack exchange,提问作者Amr

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 15:40:05