Riverpod 使用手册:Flutter 状态管理新范式

Riverpod 使用手册:Flutter 状态管理新范式

目录

Riverpod 使用手册:Flutter 状态管理新范式

一、Riverpod 是什么?

二、核心概念速查表

三、环境配置:让项目支持 Riverpod

1. 添加依赖

2. 初始化 Riverpod

四、实战 1:用 StateProvider 实现计数器

需求:一个按钮,点击后数字 +1

步骤 1:定义 Provider

步骤 2:在 Widget 中使用 Provider

效果验证

五、实战 2:用 FutureProvider 实现异步请求

需求:加载网络数据并显示

步骤 1:定义 FutureProvider

步骤 2:在 Widget 中处理异步状态

效果验证

六、实战 3:Provider 依赖与组合

需求:根据用户 ID 动态加载用户信息

步骤 1:定义 “用户 ID” 的 Provider

步骤 2:让 userProvider 依赖 userIdProvider

步骤 3:动态修改用户 ID(进阶)

七、Riverpod vs 其他框架:怎么选?

八、最佳实践:这些坑别踩!

九、总结:Riverpod 值得学吗?


一、Riverpod 是什么?

在 Flutter 开发中,状态管理是绕不开的话题。Riverpod 作为新一代状态管理框架,以简洁、灵活、强类型为核心优势,逐渐成为开发者的新宠。它解决了 Provider 框架的一些痛点,让状态管理更可控,甚至能和 GetX、Bloc 分庭抗礼!

简单说,Riverpod 是 **“状态管理的瑞士军刀”**:

  • 支持全局状态、局部状态
  • 天然兼容 Dart 空安全和异步逻辑
  • 写法简洁,学习曲线比 Bloc 平缓

接下来,咱们从 0 开始,手把手教你用 Riverpod 玩转状态管理!

二、核心概念速查表

先记住这些基础概念,后面会逐个拆解:

概念 作用 类比(Web 开发)
Provider 最基础的 “状态提供者”,返回固定值或简单计算结果 React 的 useState
StateProvider 支持修改状态的 Provider,适合简单可变状态(如开关、计数器) Vue 的 data
FutureProvider 处理异步操作(如网络请求),自动管理加载、成功、错误状态 React Query 的 useQuery
StreamProvider 处理流式数据(如实时消息、数据库监听) RxJS 的 Observable
Consumer 订阅 Provider 状态变化,触发 UI 重建 React 的 useEffect
WidgetRef 连接 Widget 和 Provider 的 “桥梁”,用于读取 / 更新状态 Vue 的 this.$store

三、环境配置:让项目支持 Riverpod

1. 添加依赖

在 pubspec.yaml 中加入:

dependencies:
  flutter_riverpod: ^2.4.0  # 核心库,必选
  riverpod_annotation: ^2.1.0  # 注解支持(可选,简化代码)
  build_runner: ^2.4.6  # 代码生成工具(配合注解时需要)

dev_dependencies:
  riverpod_generator: ^2.2.0  # 注解生成器(配合注解时需要)

然后执行 flutter pub get 安装依赖。

2. 初始化 Riverpod

在 main.dart 中,用 ProviderScope 包裹根组件:

import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  runApp(
    // 关键:所有使用 Riverpod 的组件必须在 ProviderScope 内
    const ProviderScope(
      child: MyApp(),
    ),
  );
}

ProviderScope 是 Riverpod 的 “状态容器”,负责管理所有 Provider 的生命周期。

四、实战 1:用 StateProvider 实现计数器

需求:一个按钮,点击后数字 +1

这是最基础的 “可变状态” 场景,用 StateProvider 就能轻松实现。

步骤 1:定义 Provider

新建 counter_provider.dart

import 'package:flutter_riverpod/flutter_riverpod.dart';

// 定义一个 StateProvider,初始值为 0
final counterProvider = StateProvider<int>((ref) => 0);

  • StateProvider 是 Riverpod 专门用于 **“简单可变状态”** 的工具。
  • ref 是 “Provider 上下文”,可以用来读取其他 Provider(这里暂时用不到)。
步骤 2:在 Widget 中使用 Provider

在页面组件中,用 Consumer 订阅状态:

import 'package:flutter_riverpod/flutter_riverpod.dart';

class CounterPage extends ConsumerWidget {
  const CounterPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 读取 counterProvider 的当前值
    final count = ref.watch(counterProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('Riverpod 计数器')),
      body: Center(
        child: Text(
          '计数:$count',
          style: const TextStyle(fontSize: 24),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 更新状态:读取当前值 +1
          ref.read(counterProvider.notifier).state++;
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

  • ConsumerWidget:替代传统的 StatelessWidget,让 Widget 能订阅 Provider。
  • ref.watch(provider):订阅状态,状态变化时会触发 Widget 重建。
  • ref.read(provider.notifier):获取状态的 “修改器”,用于更新值(类似 setState)。
效果验证

运行代码后:

  • 点击按钮,数字会 +1
  • 热重载时状态不会丢失(因为状态由 Riverpod 管理,而非 Widget 自身)

五、实战 2:用 FutureProvider 实现异步请求

需求:加载网络数据并显示

比如从 GitHub API 获取用户信息,需要处理加载中、成功、失败三种状态。

步骤 1:定义 FutureProvider

新建 user_provider.dart

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;

// 模拟网络请求:根据用户名获取用户信息
Future<Map<String, dynamic>> fetchUser(String username) async {
  final response = await http.get(
    Uri.parse('https://api.github.***/users/$username'),
  );
  if (response.statusCode == 200) {
    return json.decode(response.body);
  } else {
    throw Exception('加载失败');
  }
}

// 定义 FutureProvider,依赖一个用户名(这里固定为 'octocat')
final userProvider = FutureProvider<Map<String, dynamic>>((ref) {
  return fetchUser('octocat'); // GitHub 官方示例用户
});

  • FutureProvider 自动管理异步状态:
    • loading:请求中,返回 AsyncValue.loading()
    • data:请求成功,返回 AsyncValue.data(结果)
    • error:请求失败,返回 AsyncValue.error(异常)
步骤 2:在 Widget 中处理异步状态
import 'package:flutter_riverpod/flutter_riverpod.dart';

class UserPage extends ConsumerWidget {
  const UserPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 监听 userProvider 的状态变化
    final userAsync = ref.watch(userProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('GitHub 用户信息')),
      body: Center(
        child: userAsync.when(
          loading: () => const CircularProgressIndicator(), // 加载中
          error: (err, stack) => Text('错误:$err'), // 加载失败
          data: (user) => Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Image.***work(
                user['avatar_url'],
                width: 100,
                height: 100,
              ),
              const SizedBox(height: 16),
              Text(
                '用户名:${user['login']}',
                style: const TextStyle(fontSize: 18),
              ),
              Text(
                'ID:${user['id']}',
                style: const TextStyle(fontSize: 16, color: Colors.grey),
              ),
            ],
          ), // 加载成功
        ),
      ),
    );
  }
}

  • AsyncValue.when:Riverpod 提供的便捷方法,按状态分支处理 UI,比手动判断 connectionState 简洁太多!
效果验证
  • 首次进入页面:显示加载动画
  • 请求成功:显示用户头像、用户名、ID
  • 请求失败(断网时):显示错误提示

六、实战 3:Provider 依赖与组合

需求:根据用户 ID 动态加载用户信息

比如用户 ID 来自另一个 Provider,需要 “依赖注入”。

步骤 1:定义 “用户 ID” 的 Provider
final userIdProvider = Provider<String>((ref) => 'octocat');

这是一个只读 Provider,返回固定的用户 ID(实际项目中可能来自路由、全局配置等)。

步骤 2:让 userProvider 依赖 userIdProvider

修改 user_provider.dart

final userProvider = FutureProvider<Map<String, dynamic>>((ref) {
  // 读取 userIdProvider 的值
  final userId = ref.watch(userIdProvider);
  return fetchUser(userId);
});

  • ref.watch(otherProvider):在一个 Provider 中读取另一个 Provider 的值,实现依赖传递
  • 当 userIdProvider 的值变化时,userProvider 会自动重新执行请求。
步骤 3:动态修改用户 ID(进阶)

如果需要动态修改用户 ID,可以用 StateProvider

final userIdProvider = StateProvider<String>((ref) => 'octocat');

// 在 Widget 中修改:
ref.read(userIdProvider.notifier).state = 'new_user';

这样,用户 ID 变化时,userProvider 会自动重新请求新的用户信息,UI 也会同步更新。

七、Riverpod vs 其他框架:怎么选?

框架 优点 缺点 适用场景
Riverpod 强类型、写法简洁、支持复杂依赖 学习曲线比 Provider 高 中大型项目、追求类型安全
GetX 功能全(状态 + 路由 + 依赖)、上手快 过度灵活可能导致代码混乱 小型项目、快速迭代
Bloc 严格的分层(UI-Bloc-State) 样板代码多 大型项目、需要严格流程控制

简单总结:

  • 追求类型安全、复杂状态依赖 → 选 Riverpod
  • 追求极致开发速度、小而全 → 选 GetX
  • 追求严格分层、团队规范 → 选 Bloc

八、最佳实践:这些坑别踩!

  1. 避免在 Provider 中写副作用逻辑
    Provider 应该是 “纯函数”,只返回状态。副作用(如网络请求、数据库操作)尽量放在单独的服务类中。

  2. 合理使用 ref.watch 和 ref.read

    • ref.watch:在 Widget 或 Provider 中订阅状态(状态变则重建)
    • ref.read:在事件回调(如按钮点击)中一次性获取状态(不订阅)
  3. 用 family 处理动态参数
    如果 Provider 需要动态参数(如根据 ID 加载数据),可以用 family

    final userProvider = FutureProvider.family<Map, String>((ref, id) {
      return fetchUser(id);
    });
    // 使用:ref.watch(userProvider('octocat'))
    
  4. 记得清理资源
    对于 StreamProvider 或自定义的异步 Provider,必要时用 ref.onDispose 清理资源:

    final streamProvider = StreamProvider((ref) {
      final stream = ...;
      ref.onDispose(() => stream.cancel()); // 组件销毁时取消流
      return stream;
    });
    

九、总结:Riverpod 值得学吗?

非常值得! 它解决了 Flutter 状态管理的核心痛点:

  • 类型安全:告别 dynamic 地狱
  • 依赖清晰:Provider 之间的依赖关系一目了然
  • 异步友好:FutureProvider/StreamProvider 简化异步逻辑

如果你正在开发中大型 Flutter 项目,或者受够了 Provider 的一些限制,Riverpod 绝对能让你相见恨晚!

转载请说明出处内容投诉
CSS教程网 » Riverpod 使用手册:Flutter 状态管理新范式

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买