如何在Riverpod中为同一个Provider使用两种不同状态
用Riverpod实现书签功能的双状态管理方案
你可以通过自定义状态类封装两个关联状态,结合StateNotifierProvider来统一管理FAB的布尔状态和书签列表状态,确保两者的更新保持一致性。
步骤1:定义包含双状态的自定义类
创建一个BookmarkState类,把isBookmarked(控制FAB图标)和bookmarkedPages(书签页面列表)打包在一起,同时提供copyWith方法方便状态更新:
class BookmarkState { final bool isBookmarked; // 当前页面是否已收藏 final List<PageItem> bookmarkedPages; // 全局书签列表 BookmarkState({ required this.isBookmarked, required this.bookmarkedPages, }); // 复制状态并更新指定属性 BookmarkState copyWith({ bool? isBookmarked, List<PageItem>? bookmarkedPages, }) { return BookmarkState( isBookmarked: isBookmarked ?? this.isBookmarked, bookmarkedPages: bookmarkedPages ?? this.bookmarkedPages, ); } } // 自定义页面模型(根据你的实际业务调整) class PageItem { final String id; final String title; PageItem({required this.id, required this.title}); }
步骤2:创建StateNotifier管理状态逻辑
用StateNotifier封装状态更新的业务逻辑,实现切换书签的方法,确保两个状态同步更新:
class BookmarkNotifier extends StateNotifier<BookmarkState> { // 初始状态:未收藏,书签列表为空 BookmarkNotifier() : super(BookmarkState(isBookmarked: false, bookmarkedPages: [])); // 切换当前页面的书签状态 void toggleBookmark(PageItem currentPage) { // 检查当前页面是否已在书签列表中 final isAlreadyBookmarked = state.bookmarkedPages.any((page) => page.id == currentPage.id); List<PageItem> updatedList; if (isAlreadyBookmarked) { // 已收藏则移除 updatedList = state.bookmarkedPages.where((page) => page.id != currentPage.id).toList(); } else { // 未收藏则添加 updatedList = [...state.bookmarkedPages, currentPage]; } // 更新状态:同步切换isBookmarked和书签列表 state = state.copyWith( isBookmarked: !isAlreadyBookmarked, bookmarkedPages: updatedList, ); } } // 创建全局Provider final bookmarkProvider = StateNotifierProvider<BookmarkNotifier, BookmarkState>((ref) { return BookmarkNotifier(); });
步骤3:UI中使用状态
在FAB组件和书签页面列表中,通过Consumer监听bookmarkProvider的状态变化:
控制FAB图标
Consumer( builder: (context, ref, child) { final bookmarkState = ref.watch(bookmarkProvider); // 假设currentPage是当前页面的实例 return FloatingActionButton( onPressed: () => ref.read(bookmarkProvider.notifier).toggleBookmark(currentPage), child: Icon( bookmarkState.isBookmarked ? Icons.bookmark : Icons.bookmark_border, ), ); }, )
显示书签列表页面
Consumer( builder: (context, ref, child) { final bookmarkState = ref.watch(bookmarkProvider); return ListView.builder( itemCount: bookmarkState.bookmarkedPages.length, itemBuilder: (context, index) { final page = bookmarkState.bookmarkedPages[index]; return ListTile( title: Text(page.title), // 可添加跳转、删除等操作 ); }, ); }, )
可选优化:持久化书签列表
如果需要重启App后保留书签,可以在BookmarkNotifier初始化时从本地存储(如SharedPreferences、Hive)加载数据,更新状态:
BookmarkNotifier() : super(BookmarkState(isBookmarked: false, bookmarkedPages: [])) { _loadSavedBookmarks(); } Future<void> _loadSavedBookmarks() async { // 示例:从SharedPreferences读取书签数据 final prefs = await SharedPreferences.getInstance(); final savedPages = prefs.getStringList('bookmarked_pages') ?? []; final parsedPages = savedPages.map((id) => PageItem(id: id, title: '页面$id')).toList(); state = state.copyWith(bookmarkedPages: parsedPages); } // 在toggleBookmark方法中添加保存逻辑 void toggleBookmark(PageItem currentPage) { // ... 原有逻辑 ... // 保存到本地 final prefs = await SharedPreferences.getInstance(); final pageIds = state.bookmarkedPages.map((page) => page.id).toList(); await prefs.setStringList('bookmarked_pages', pageIds); }
内容的提问来源于stack exchange,提问作者Ziad H.
相关产品推荐
相关产品推荐

