Flutter状态管理插件reactive_state_machine的使用

Flutter状态管理插件reactive_state_machine的使用

reactive_state_machine 提供了一种灵活且用户友好的方法来创建反应式层次化的有限状态机。它是用纯 Dart 编写的。

注意:此包尚未达到生产就绪状态。未来版本可能会更改 API。

该包引入了两种类型的 StateMachines。它们都是层次化的有限状态机,但定义和使用状态和转换的方式不同。两者都实现了 StateMachineBase 接口。

  • EventStateMachine 是一种从事件总线接收输入的状态机。事件基于当前状态进行处理,并可能触发副作用或状态转换。它在状态机应响应流时或需要同时管理多个事件源时工作最佳。

  • CommandStateMachine 是一种通过调用状态的方法进行交互的状态机。这种机器设计用于利用 Dart 的模式匹配功能,通过显式定义允许的转换来实现编译时安全的交互。它在消费者希望以命令方式与状态机交互时工作最佳。

转换和事件处理依赖于 StateEvent 类型,而不是对象相等性。

状态机不强制特定的反应式 API,给开发者选择实现(如 StreamChangeNotifierBehaviorSubject 等)的灵活性。

该包包括两种机器类型基于 Dart Stream 的实现:StreamEventStateMachineStreamCommandStateMachine

flutter_reactive_state_machine 包为 Flutter 的标准 Listenable 提供了额外的实现,并提供了其他专门为 Flutter 定制的工具。

EventStateMachine

sealed class State {
  const State();
}

class Green extends State {
  const Green();
}

class Red extends State {
  const Red();
}

class Orange extends State {
  const Orange();
}

sealed class Event {
  const Event();
}

class TimerFinished extends Event {
  const TimerFinished();
}

final class TraficLight extends StreamEventStateMachine<State, Event> {
  TraficLight(super.initial);

  @override
  late final states = {
    // Green state
    define<Green> (($) => $
      ..onEnter(_startTimer)
      ..on<TimerFinished>((state, event) => const Orange())),

    // Orange state
    define<Orange> (($) => $
      ..onEnter(_startTimer)
      ..on<TimerFinished>((state, event) => const Red())),

    // Red state
    define<Red> (($) => $
      ..onEnter(_startTimer)
      ..on<TimerFinished>((state, event) => const Green())),
  };

  void _startTimer(_) {
    Timer(Duration(seconds: 1), () => add(const TimerFinished()));
  }
}

CommandStateMachine

sealed class UserState with State<UserModel, UserState> {}

class Unknown extends UserState {
  @override
  Future<void> onEnter() async {
    final user = await machine.authenticationService.currentUser();
    if (user != null) {
      transitionTo(Authenticated(user));
    } else {
      transitionTo(Unauthenticated());
    }
  }
}

class Unauthenticated extends UserState {
  Future<bool> login() async {
    final user = await machine.authenticationService.tryLogin();
    if (user != null) {
      transitionTo(Authenticated(user));
      return true;
    } else {
      return false;
    }
  }
}

class Authenticated extends UserState {
  Authenticated(this.user);

  final User user;

  Future<void> logout() async {
    await machine.authenticationService.logout();
    transitionTo(Unauthenticated());
  }
}

final class UserModel extends StreamCommandStateMachine<UserState> {
  UserModel({
    required this.authenticationService,
  }) : super(Unknown());

  final AuthenticationService authenticationService;
}

使用示例

void main() async {
  final machine = MyStateMachine();

  if (machine.state case SomeState state) {
    state.yourData;
  }

  machine.ifState((TestState state) => state.doSomething());

  final content = switch (machine.state) {
    StateA() || StateB() => "A or B",
    StateC() => "C",
  };
}

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

1 回复

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


reactive_state_machine 是一个轻量级的 Flutter 状态管理插件,它基于状态机的概念,允许开发者通过定义状态和事件来管理应用的状态。它非常适合用于复杂的 UI 交互和状态转换场景。

安装

首先,你需要在 pubspec.yaml 文件中添加 reactive_state_machine 依赖:

dependencies:
  flutter:
    sdk: flutter
  reactive_state_machine: ^0.1.0

然后运行 flutter pub get 来安装依赖。

基本概念

  1. State(状态): 应用在某一时刻的状态。每个状态可以包含一些数据。
  2. Event(事件): 触发状态转换的动作。事件可以携带数据。
  3. State Machine(状态机): 管理状态和状态转换的逻辑。

使用步骤

1. 定义状态和事件

首先,你需要定义应用的状态和事件。这些通常是枚举类型。

enum MyState { initial, loading, loaded, error }
enum MyEvent { fetchData, dataFetched, errorOccurred }

2. 创建状态机

接下来,创建一个状态机并定义状态转换逻辑。

import 'package:reactive_state_machine/reactive_state_machine.dart';

final stateMachine = StateMachine<MyState, MyEvent>(
  initialState: MyState.initial,
  transitions: {
    MyState.initial: {
      MyEvent.fetchData: MyState.loading,
    },
    MyState.loading: {
      MyEvent.dataFetched: MyState.loaded,
      MyEvent.errorOccurred: MyState.error,
    },
    MyState.loaded: {
      MyEvent.fetchData: MyState.loading,
    },
    MyState.error: {
      MyEvent.fetchData: MyState.loading,
    },
  },
);

3. 监听状态变化

你可以通过 stateMachine.stateStream 来监听状态的变化。

stateMachine.stateStream.listen((state) {
  print('Current state: $state');
});

4. 触发事件

通过 stateMachine.trigger 方法来触发事件,从而驱动状态转换。

stateMachine.trigger(MyEvent.fetchData);

5. 在 Flutter 中使用

你可以在 Flutter 的 StatefulWidget 中使用 StateMachine 来管理状态。

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

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final stateMachine = StateMachine<MyState, MyEvent>(
    initialState: MyState.initial,
    transitions: {
      MyState.initial: {
        MyEvent.fetchData: MyState.loading,
      },
      MyState.loading: {
        MyEvent.dataFetched: MyState.loaded,
        MyEvent.errorOccurred: MyState.error,
      },
      MyState.loaded: {
        MyEvent.fetchData: MyState.loading,
      },
      MyState.error: {
        MyEvent.fetchData: MyState.loading,
      },
    },
  );

  [@override](/user/override)
  void initState() {
    super.initState();
    stateMachine.stateStream.listen((state) {
      setState(() {});
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Reactive State Machine Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            if (stateMachine.currentState == MyState.initial)
              Text('Initial State'),
            if (stateMachine.currentState == MyState.loading)
              CircularProgressIndicator(),
            if (stateMachine.currentState == MyState.loaded)
              Text('Data Loaded!'),
            if (stateMachine.currentState == MyState.error)
              Text('Error Occurred!'),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                stateMachine.trigger(MyEvent.fetchData);
              },
              child: Text('Fetch Data'),
            ),
          ],
        ),
      ),
    );
  }
}

void main() => runApp(MaterialApp(home: MyApp()));
回到顶部