Riverpod使用

听好多人说riverpod上手比较难度比较高,所以结合使用了几年riverpod的经验写一个入门使用教程。

准备工作

dart 复制代码
dependencies:
  flutter_riverpod: ^3.0.3
dart 复制代码
void main() { runApp(const ProviderScope(child: MyApp()), ); }

常用的provider

这个provider只是一种叫法,你可以理解为controller也可以

我自己写了很多的项目中常用的provider只有两种 StateProvider, StateNotifierProvider

可能偶尔会用到StreamProvider使用场景比如模拟网络速度的变化

dart 复制代码
// 每秒中随机一个速度
final mediaSpeedProvider = StreamProvider.autoDispose<int>(
  (ref) => Stream.periodic(
    const Duration(milliseconds: 1000),
    (e) => Random().nextInt(100),
  ),
);

// widget部分
class Temp extends ConsumerWidget {
  const Temp({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final speed = ref.watch(mediaSpeedProvider).value ?? 0;
    return Text("current network speed ${speed}kb")
  }
}

这里顺便说一下autoDispose它取决于你要不要这个provider的state常驻在app里面, 通俗的讲只要app不死这个provider的值就一直在。

或者换一个说法你要不要这个provider在没有人watch它的时候释放他。

StateProvider使用场景

使用单一数据类型的时候比如bool、int、string、List、Map、或者你的model。

dart 复制代码
final mediaProvider = StateProvider((ref) => 0.0);
final mediaStatusProvider = StateProvider<int>((ref) => 0);
final copySuccessProvider = StateProvider.autoDispose<bool>((ref) => false);

// 当数据发生变化时
commonRef?.read(mediaStatusProvider.notifier).state = 2;

这里顺便说一下ref,ref相当于一个句柄可以拿到所有provider,ref可以通过ConsumerWidget或者ConsumerStatefulWidget。

如果你不方便拿到ref也可以在全局声明一个比如commRef, 然后在root_page给commRef赋值

其实可以不用深究ref到底是个啥,你只要知道一点没有ref你的provider就都用不。

StateNotifierProvider使用场景

当你的需要多个值去更新ui时,比如一个网络请求

dart 复制代码
import 'package:hugebox/common/network/network.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'file_list_provider.g.dart';

@Riverpod(keepAlive: true)
class FileListNotifier extends _$FileListNotifier {
  int page = 1;
  int pageSize = 10;
  @override
  FileListState build() {
    refresh();
    return FileListState();
  }

  void clear() async {
    state = state.copyWith(list: []);
  }

  Future<void> refresh() async {
    page = 1;
    final res = await NetworkTool.request(
      API.open_directory,
      params: {
        "uid": user?.id,
        "page": page, //页面
        "size": pageSize, //分页大小
        "sorts": [sortStr] //排序方式
      },
    );
    final list = List<FileListModel>.from(res.map((x) => FileListModel.fromJson(x)));
    state = state.copyWith(
      list: list,
      isLoading: false,
      noMore: list.length < pageSize,
    );
  }

  Future<bool> loadMore() async {
    final res = await NetworkTool.request(
      API.open_directory,
      params: {
        "uid": user?.id,
        "page": page, //页面
        "size": pageSize, //分页大小
        "sorts": [sortStr] //排序方式
      },
    );
    final list = List<FileListModel>.from(res.map((x) => FileListModel.fromJson(x)));
    state = state.copyWith(
      list: [...state.list, ...list],
      isLoading: false,
      noMore: list.length < pageSize,
    );
    return list.length < pageSize;
  }
}

class FileListState {
  final List<FileListModel> list;
  final bool noMore;
  final bool isLoading;

  FileListState({this.list = const [], this.noMore = false, this.isLoading = true});

  FileListState copyWith({
    List<FileListModel>? list,
    bool? noMore,
    bool? isLoading,
  }) {
    return FileListState(
      list: list ?? this.list,
      noMore: noMore ?? this.noMore,
      isLoading: isLoading ?? this.isLoading,
    );
  }
}

// widget部分
class Temp extends ConsumerWidget {
  const Temp({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final state = ref.watch(fileListNotifierProvider);
    ref.listen(fileListNotifierProvider, (old, newValue) {
      _controller.finishLoad(newValue.noMore ? IndicatorResult.noMore : IndicatorResult.success);
    });
    return xxWidget;
  }
}

顺便说一下listen的,就是监听provider state的变化,比如请求成功之后需要结束刷新控件的刷新状态。

关于传参

上个StateNotifireProvider使用的是注解的形式可以省去一些工作量,如果不使用注解的话需要自己去实现Notifier比较麻烦推荐使用注解。

传参数直接在build方法里面加就可以了, 这个provider的state还和上面那个FileListNotifier的state是共用的。

dart 复制代码
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'file_child_list_provider.g.dart';

@Riverpod(keepAlive: true)
class FileChildListNotifier extends _$FileChildListNotifier {
  int page = 1;
  int pageSize = 20;
  @override
  FileListState build(String? dirId) {
    return FileListState();
  }

  Future<void> refresh() async {
//    xxxx
    state = state.copyWith(list: list, isLoading: false);
  }

  Future<bool> loadMore() async {
     // xxx
     state = state.copyWith(list: list, isLoading: false);
  }
}

// 调用方式
ref.read(fileChildListNotifierProvider(childId).notifier).refresh();

// widget
class Temp extends ConsumerWidget {
  const Temp({super.key});

  @override
  Widget build(BuildContext context, ref) {
    final state = ref.watch(fileChildListNotifierProvider(childId));
    ref.listen(fileChildListNotifierProvider(childId), (old, newValue) {
      _controller.finishLoad(newValue.noMore ? IndicatorResult.noMore : IndicatorResult.success);
    });
    return xxWidget;
  }
}

以上2种基本上可以满足大部分的开发需求了。 关于riverpod3.0+的一些高级的比如重试、override用法目前没有用到。

相关推荐
恋猫de小郭1 小时前
Flutter iOS 的深度优化 PR,搞笑的是贡献者被 Gemini 评审折磨
android·前端·flutter
GitLqr15 小时前
Flutter + Unity 混合开发:用 unity_kit 实现高效的双向通信
flutter·unity3d·全栈
程序员老刘19 小时前
Flutter版本选择指南:3.47压哨发布,9月大限只剩一周 | 2026年8月
flutter·ai编程·客户端
xcyxiner1 天前
flutter 运行到模拟器上
android·前端·flutter
末代iOS程序员华仔1 天前
iOS 语聊直播/聊天APP4.3条例被拒解决
flutter·ios·swift
恋猫de小郭1 天前
Dart 3.13 的到底改了什么?为什么很重要?有什么坑?
android·前端·flutter
xcyxiner2 天前
flutter wsl2安装记录(使用宿主机虚拟机)
前端·flutter
Kevin Coding2 天前
JsonConvert:适用于 Android、鸿蒙与 Flutter 的 JSON 转 Model 插件
android·flutter·harmonyos
iFlyCai3 天前
Flutter原理深度解析:从架构到渲染的全面剖析(二)
flutter·flutter 三棵树
里欧跑得慢3 天前
CSS 模块化架构的演进:BEM、CSS Modules 到 CSS-in-JS 的反思
前端·css·flutter·web·css-in-js