Flutter状态管理插件replay_riverpod的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter状态管理插件replay_riverpod的使用


引言

replay_riverpod 是一个扩展了 riverpod 的插件,它为 riverpod 状态添加了自动的撤销和重做支持。这与 package:replay_bloc 类似。

学习更多关于 replay_riverpod 的信息可以访问 riverpod.dev


创建一个 ReplayStateNotifier

要创建一个 ReplayStateNotifier,你需要继承 ReplayStateNotifier 并指定状态类型。例如,下面是一个用于管理整数计数器的 CounterNotifier

class CounterNotifer extends ReplayStateNotifier<int> {
  CounterNotifer() : super(0);

  void increment() => emit(state + 1);
}

使用一个 CounterNotifier

main 函数中,你可以创建一个 CounterNotifier 实例,并通过调用其方法来触发状态变化。你还可以使用 undoredo 方法来撤销或重做这些状态变化。

void main() {
  final notifier = CounterNotifer();

  // 触发状态变化
  notifier.increment();
  print(notifier.state); // 输出: 1

  // 撤销状态变化
  notifier.undo();
  print(notifier.state); // 输出: 0

  // 重做状态变化
  notifier.redo();
  print(notifier.state); // 输出: 1
}

使用 ReplayStateNotifierMixin

如果你希望在一个不同的状态管理器(如 HydratedStateNotifier)中使用 ReplayStateNotifier,你可以使用 ReplayStateNotifierMixin

class CounterNotifier extends HydratedStateNotifier<int> with ReplayStateNotifierMixin {
  CounterNotifier() : super(0);

  void increment() => emit(state + 1);
  void decrement() => emit(state - 1);

  [@override](/user/override)
  int fromJson(Map<String, dynamic> json) => json['value'] as int;

  [@override](/user/override)
  Map<String, int> toJson(int state) => {'value': state};
}

完整示例 Demo

以下是一个完整的示例代码,展示了如何使用 replay_riverpod 插件来管理一个计数器的状态。

import 'package:flutter/material.dart';
import 'package:replay_riverpod/replay_riverpod.dart';

void main() {
  runApp(ProviderScope(observers: [AppProviderObserver()], child: const App()));
}

/// 自定义的 [ProviderObserver],观察所有通知器状态的变化。
class AppProviderObserver extends ProviderObserver {
  [@override](/user/override)
  void didUpdateProvider(
    ProviderBase provider,
    Object? previousValue,
    Object? newValue,
    ProviderContainer container,
  ) {
    print('''
{
  "provider": "${provider.name ?? provider.runtimeType}",
  "newValue": "$newValue"
}''');
  }
}

/// {[@template](/user/template) app}
/// 一个 [StatelessWidget],使用 [replay_riverpod](https://pub.dev/packages/replay_riverpod)
/// 来管理计数器的状态。
/// {[@endtemplate](/user/endtemplate)}
class App extends StatelessWidget {
  /// {[@macro](/user/macro) app}
  const App({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: CounterPage(),
    );
  }
}

/// {[@template](/user/template) counter_page}
/// 一个 [StatelessWidget],展示如何消费和与一个 [ReplayStateNotifier] 交互。
/// {[@endtemplate](/user/endtemplate)}
class CounterPage extends ConsumerWidget {
  /// {[@macro](/user/macro) counter_page}
  const CounterPage({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context, WidgetRef ref) {
    final textTheme = Theme.of(context).textTheme;
    return Scaffold(
      appBar: AppBar(
        title: const Text('Counter'),
        actions: [
          Consumer(
            builder: (context, ref, child) {
              final counter = ref.read(_counterProvider.notifier);
              return IconButton(
                icon: const Icon(Icons.undo),
                onPressed: counter.canUndo ? counter.undo : null,
              );
            },
          ),
          Consumer(
            builder: (context, ref, child) {
              final counter = ref.read(_counterProvider.notifier);
              return IconButton(
                icon: const Icon(Icons.redo),
                onPressed: counter.canRedo ? counter.redo : null,
              );
            },
          ),
        ],
      ),
      body: Center(
        child: Consumer(
          builder: (context, ref, child) {
            final state = ref.watch(_counterProvider);
            return Text('$state', style: textTheme.headline2);
          },
        ),
      ),
      floatingActionButton: Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          FloatingActionButton(
            child: const Icon(Icons.add),
            onPressed: () {
              ref.read(_counterProvider.notifier).increment();
            },
          ),
          const SizedBox(height: 4),
          FloatingActionButton(
            child: const Icon(Icons.remove),
            onPressed: () {
              ref.read(_counterProvider.notifier).decrement();
            },
          ),
          const SizedBox(height: 4),
          FloatingActionButton(
            child: const Icon(Icons.delete_forever),
            onPressed: () {
              ref.read(_counterProvider.notifier).reset();
            },
          ),
        ],
      ),
    );
  }
}

/// {[@template](/user/template) replay_counter_notifier}
/// 一个简单的 [ReplayStateNotifier],管理一个整数状态,并提供了三个公共方法:
/// `increment`,`decrement` 和 `reset` 来操作状态。
/// {[@endtemplate](/user/endtemplate)}
class CounterNotifier extends ReplayStateNotifier<int> {
  /// {[@macro](/user/macro) replay_counter_notifier}
  CounterNotifier() : super(0);

  /// 将 [CounterNotifier] 状态增加 1。
  void increment() => emit(state + 1);

  /// 将 [CounterNotifier] 状态减少 1。
  void decrement() => emit(state - 1);

  /// 将 [CounterNotifier] 状态重置为 0。
  void reset() => emit(0);
}

// 定义一个 StateNotifierProvider,用于提供 CounterNotifier 实例。
final _counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) => CounterNotifier());

更多关于Flutter状态管理插件replay_riverpod的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter状态管理插件replay_riverpod的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何使用 replay_riverpod 进行状态管理的 Flutter 代码示例。replay_riverpod 是 Riverpod 状态管理库的一个扩展,它允许我们在应用生命周期内重新播放状态变化,这对于调试和测试非常有用。

首先,确保你的 Flutter 项目已经添加了 riverpodreplay_riverpod 依赖。在 pubspec.yaml 文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_riverpod: ^1.0.0  # 请使用最新版本
  replay_riverpod: ^0.1.0    # 请使用最新版本

然后,运行 flutter pub get 来获取这些依赖。

接下来,让我们创建一个简单的 Flutter 应用,演示如何使用 replay_riverpod 进行状态管理。

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:replay_riverpod/replay_riverpod.dart';

void main() {
  // 创建一个 Riverpod ProviderContainer,并启用 Replay 功能
  final container = ProviderContainer(
    overrides: [
      replayProviderFamilyOverride, // 启用 Replay 功能
    ],
  );

  runApp(
    ProviderScope.container(container: container, child: MyApp()),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Replay Riverpod Demo')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              CounterButton(),
              ReplayButton(),
            ],
          ),
        ),
      ),
    );
  }
}

final counterProvider = StateNotifierProvider<Counter, int>((ref) {
  return Counter();
});

class Counter extends StateNotifier<int> {
  Counter() : super(0);

  void increment() {
    state++;
  }
}

class CounterButton extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return ElevatedButton(
      onPressed: () => ref.read(counterProvider.notifier).increment(),
      child: Text('Increment ($count)'),
    );
  }
}

class ReplayButton extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 获取 ReplayController
    final replayController = ref.read(replayControllerProvider);

    return ElevatedButton(
      onPressed: replayController.isReplaying
          ? null // 如果正在重放,禁用按钮
          : () {
              // 开始重放状态变化
              replayController.replay();
            },
      child: replayController.isReplaying
          ? Text('Stop Replay')
          : Text('Start Replay'),
    );
  }
}

解释

  1. ProviderContainer: 在 main 函数中,我们创建了一个带有 replayProviderFamilyOverrideProviderContainer,这启用了 Replay 功能。

  2. CounterProvider: 我们定义了一个简单的 StateNotifierProvider,它管理一个整数计数器状态。

  3. Counter 和 CounterButton: Counter 类是一个 StateNotifier,它包含一个 increment 方法来增加计数。CounterButton 是一个 ConsumerWidget,它监听 counterProvider 的状态并显示当前计数,同时提供一个按钮来增加计数。

  4. ReplayButton: 另一个 ConsumerWidget,它监听 replayControllerProvider。这个按钮用于开始或停止状态重放。如果正在重放,按钮会显示 “Stop Replay” 并禁用点击;否则,显示 “Start Replay” 并允许开始重放。

  5. ReplayController: 通过 ref.read(replayControllerProvider) 获取 ReplayController 实例,并调用其 replay 方法开始重放状态变化。

这个示例展示了如何使用 replay_riverpod 来重放应用的状态变化,这对于调试和测试状态管理逻辑非常有帮助。你可以根据需要扩展和修改这个示例。

回到顶部