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

如何在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.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 18:22:44