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用法目前没有用到。

相关推荐
消失的旧时光-194319 小时前
iFlutter --> Flutter 开发者 的 IntelliJ IDEA / Android Studio 插件
flutter·android studio·intellij-idea
马拉萨的春天1 天前
block的样式有哪些?如果copy的话分别会有啥样式
flutter·性能优化·ios的block
Rattenking1 天前
【CSS】---- 图形函数详解
笔记·学习·flutter
程序员老刘1 天前
别再抱怨Flutter方案太多了,这个就叫生态!
flutter·客户端
黄毛火烧雪下1 天前
(一)Flutter 插件项目demo预览图
flutter
站在远方望童年1 天前
WSL2 中的 Flutter 开发环境配置
flutter
w_y_fan1 天前
flutter_native_splash: ^2.4.7
android·前端·flutter
QuantumLeap丶1 天前
《Flutter全栈开发实战指南:从零到高级》- 06 -常用布局组件
flutter·dart
大雷神2 天前
【成长纪实】Flutter中Dart 与Harmony中 ArkTS 异步编程对比:从 Future 到 Promise
flutter·harmonyos