如何为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
相关产品推荐
相关产品推荐

