Flutter状态管理插件mobx_widget的使用

Flutter状态管理插件mobx_widget的使用

引言

mobx_widget 是一个用于在 Flutter 中处理 MobX 观察者对象的便捷库。它提供了几个有用的 widget,如 ObserverFuture, ObserverStream, 和 ObserverText,这些 widget 可以帮助你轻松地将 MobX 观测数据与 UI 结合起来。

安装

首先,你需要将 mobx_widget 添加到你的项目依赖中。打开 pubspec.yaml 文件,并添加以下依赖:

dependencies:
  mobx_widget: ^0.5.1

然后运行 flutter pub get 来获取该包。

导入并使用观察者 widget

接下来,在你的 Dart 文件中导入 mobx_widget 包,并开始使用这些 widget。

import 'package:mobx_widget/mobx_widget.dart';

示例代码

以下是一个完整的示例代码,展示了如何在 Flutter 应用程序中使用 mobx_widget

import 'package:example/my_custom_widget.dart'; // 自定义 widget
import 'package:example/my_store.dart'; // 存储类
import 'package:flutter/material.dart';
import 'package:mobx_widget/mobx_widget.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'MobX Widget Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        primaryColor: Colors.blue,
        accentColor: Colors.green,
      ),
      home: MyHomePage(title: 'MobX Widget Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, this.title}) : super(key: key);
  final String? title;
  [@override](/user/override)
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late MyStore myStore;

  [@override](/user/override)
  void initState() {
    super.initState();
    myStore = MyStore();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    double screenWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title ?? 'VAZIO**'),
      ),
      body: Stack(
        fit: StackFit.expand,
        children: <Widget>[
          Positioned(
            bottom: 0,
            child: Container(
              height: 100,
              width: screenWidth,
              color: Colors.amber,
              child: ObserverFuture<String, Exception>(
                // retry: 2,
                listen: (observableFuture) {
                  print(observableFuture?.status);
                },
                // fetchData: () {
                //   myStore.fetch();
                // },
                transition: Transition(
                  transition: TransitionType.slideVertical,
                  duration: Duration(seconds: 1),
                ),
                onNull: (_) {
                  return Center(
                      key: ObserverKeyOnNull,
                      child: Text('(on null)',
                          style: TextStyle(color: Colors.white, fontSize: 20)));
                },
                observableFuture: () => myStore.observableFuture,
                onData: (_, data) => Center(
                  key: ObserverKeyOnData,
                  child: Text(
                    data,
                    style: TextStyle(color: Colors.white, fontSize: 40),
                  ),
                ),
                onUnstarted: (_) => Center(
                  key: ObserverKeyOnUnstarted,
                  child: Text(
                    '(unstarted)',
                    style: TextStyle(color: Colors.white, fontSize: 20),
                  ),
                ),
                onPending: (_) => Center(
                    key: ObserverKeyOnPending,
                    child: CircularProgressIndicator()),
                onError: (_, error) {
                  return Center(
                      key: UniqueKey(),
                      child: Text(error.toString(),
                          style: TextStyle(color: Colors.white, fontSize: 20)));
                },
              ),
            ),
          ),
          DefaultTextStyle(
            textAlign: TextAlign.center,
            style: TextStyle(fontSize: 20, color: Colors.blue),
            child: SingleChildScrollView(
              child: Column(
                // crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  SizedBox(height: 40),
                  Text(
                    'ObservableStream:',
                  ),
                  ClipRRect(
                    borderRadius: BorderRadius.circular(10),
                    child: Container(
                      color: Colors.black26,
                      alignment: Alignment.centerLeft,
                      width: screenWidth * .9,
                      child: ObserverStream<double, dynamic>(
                        transition: Transition(
                            transition: TransitionType.sizeHorizontal,
                            duration: Duration(milliseconds: 100)),
                        observableStream: () => myStore.observableStream2,
                        onData: (_, data) => Container(
                            width:
                                data != null ? screenWidth * (data / 100) : 0,
                            color: Colors.green,
                            height: 28,
                            key: ObserverKeyOnData),
                        onUnstarted: (_) => Container(
                            color: Colors.green,
                            height: 28,
                            width: 0,
                            key: ObserverKeyOnUnstarted),
                      ),
                    ),
                  ),
                  SizedBox(
                    height: 20,
                  ),
                  Divider(),
                  Container(
                    width: double.infinity,
                    child: ObserverStream<String, String>(
                      transition: Transition(
                        duration: Duration(seconds: 2),
                        transition: TransitionType.slideHorizontalDismiss,
                        curveIn: Curves.linear,
                        curveOut: Curves.linear,
                      ),
                      observableStream: () => myStore.observableStream,
                      onData: (_, data) =>
                          Text('DATA: $data', key: ObserverKeyOnData),
                      onNull: (_) => Text(
                        'NULL',
                        key: ObserverKeyOnNull,
                        style: TextStyle(color: Colors.green),
                      ),
                      onUnstarted: (_) => Text('UNSTARTED',
                          key: ObserverKeyOnUnstarted,
                          style: TextStyle(color: Colors.grey)),
                      onError: (_, error) => Text('ERROR: ' + error,
                          key: ObserverKeyOnError,
                          style: TextStyle(color: Colors.red)),
                    ),
                  ),
                  Divider(),
                  ObserverStream<String, String>(
                    transition: Transition(
                      duration: Duration(seconds: 2),
                      transition: TransitionType.slideVerticalDismiss,
                    ),
                    observableStream: () => myStore.observableStream,
                    onData: (_, data) =>
                        Text('DATA: $data', key: ObserverKeyOnData),
                    onNull: (_) => Text(
                      'NULL',
                      key: ObserverKeyOnNull,
                      style: TextStyle(color: Colors.green),
                    ),
                    onUnstarted: (_) => Text('UNSTARTED',
                        key: ObserverKeyOnUnstarted,
                        style: TextStyle(color: Colors.grey)),
                    onError: (_, error) => Text('ERROR: ' + error,
                        key: ObserverKeyOnError,
                        style: TextStyle(color: Colors.red)),
                  ),
                  Divider(),
                  ObserverStream<String, String>(
                    transition: Transition(
                      duration: Duration(seconds: 2),
                      transition: TransitionType.slideVertical,
                    ),
                    observableStream: () => myStore.observableStream,
                    onData: (_, data) =>
                        Text('DATA: $data', key: ObserverKeyOnData),
                    onNull: (_) => Text(
                      'NULL',
                      key: ObserverKeyOnNull,
                      style: TextStyle(color: Colors.green),
                    ),
                    onUnstarted: (_) => Text('UNSTARTED',
                        key: ObserverKeyOnUnstarted,
                        style: TextStyle(color: Colors.grey)),
                    onError: (_, error) => Text('ERROR: ' + error,
                        key: ObserverKeyOnError,
                        style: TextStyle(color: Colors.red)),
                  ),
                  Divider(),
                  ObserverStream<String, String>(
                    transition: Transition(
                        duration: Duration(seconds: 2),
                        transition: TransitionType.slideHorizontal),
                    observableStream: () => myStore.observableStream,
                    onData: (_, data) =>
                        Text('DATA: $data', key: ObserverKeyOnData),
                    onNull: (_) => Text(
                      'NULL',
                      key: ObserverKeyOnNull,
                      style: TextStyle(color: Colors.green),
                    ),
                    onUnstarted: (_) => Text('UNSTARTED',
                        key: ObserverKeyOnUnstarted,
                        style: TextStyle(color: Colors.grey)),
                    onError: (_, error) => Text('ERROR: ' + error,
                        key: ObserverKeyOnError,
                        style: TextStyle(color: Colors.red)),
                  ),
                  Divider(),
                  ObserverText(
                    transition: Transition(
                      transition: TransitionType.fade,
                      duration: Duration(seconds: 1),
                      curveIn: Curves.linear,
                      curveOut: Curves.linear,
                    ),
                    onData: (_) => 'ObserverText:\n${myStore.text}',
                    // style: Theme.of(context).textTheme.bodyText1,
                  ),
                  SizedBox(height: 20),
                  Divider(),
                  Text(
                    'ObservableFuture:',
                  ),
                  ObserverFuture(
                    // showDefaultProgressInOverlay: true,
                    // overlayWidget: Container(
                    //   color: Theme.of(context).backgroundColor.withOpacity(.4),
                    //   child: Center(
                    //     child: Container(
                    //       padding: EdgeInsets.all(24),
                    //       decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(10)),
                    //       width: 100,
                    //       height: 100,
                    //       child: CircularProgressIndicator(),
                    //     ),
                    //   ),
                    // ),

                    transition: Transition(
                      transition: TransitionType.slideHorizontal,
                      duration: Duration(seconds: 1),
                    ),

                    // retry: 1,
                    autoInitialize: false,
                    fetchData: myStore.fetch,
                    observableFuture: () => myStore.observableFuture,
                    onData: (_, data) => Text(
                      '😊',
                      key: ObserverKeyOnNull,
                    ),
                    onNull: (_) => Text(
                      '🙄',
                      key: ObserverKeyOnNull,
                    ),
                    onError: (_, error) => Text(
                      '😥',
                      key: ObserverKeyOnError,
                    ),
                    onUnstarted: (_) => Text(
                      '😐',
                      key: ObserverKeyOnUnstarted,
                    ),
                    onPending: (_) => Text('🤔', key: ObserverKeyOnPending),
                  ),
                  SizedBox(
                    height: 16,
                  ),
                  Divider(),
                  Text(
                    'MyCustomObserverFuture:',
                  ),
                  MyCustomObserverFutureWidget(
                    observableFuture: () => myStore.observableFuture,
                    onData: (_, data) => Icon(
                      Icons.ac_unit,
                      key: ObserverKeyOnData,
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  [@override](/user/override)
  void dispose() {
    myStore.dispose();
    super.dispose();
  }
}

自定义行为

你还可以自定义 ObserverFuture 的行为,以便在整个应用程序中重复使用。例如,你可以创建一个自定义的 ObserverFuture widget。

class MyCustomObserverFutureWidget extends StatelessWidget {
  final ObservableFuture Function() observableFuture;
  final Function(BuildContext context, dynamic data) onData;

  MyCustomObserverFutureWidget({Key key, this.observableFuture, this.onData}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return ObserverFuture(
      observableFuture: observableFuture,
      onData: onData,
      onNull: (_) => Text('🤔'),
      onError: (_, error) => Text('😥'),
      onUnstarted: (_) => Text('😐'),
      onPending: (_) => Text('👂👂👂'),
      showDefaultProgressInOverlay: true,
      overlayWidget: Container(
        color: Colors.black45,
        child: Text('👀💬', style: TextStyle(fontSize: 40)),
        alignment: Alignment.center,
      ),
    );
  }
}

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

1 回复

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


当然,下面是一个关于如何在Flutter中使用mobx_widget插件进行状态管理的代码示例。mobx_widget是一个将MobX与Flutter结合使用的库,它允许你使用MobX的响应式状态管理特性来构建你的Flutter应用。

首先,确保你的pubspec.yaml文件中包含了必要的依赖项:

dependencies:
  flutter:
    sdk: flutter
  mobx: ^2.0.6 # 请检查最新版本
  mobx_flutter: ^2.0.4 # 请检查最新版本
  mobx_codegen: ^2.0.5 # 请检查最新版本(用于生成代码)
  build_runner: ^2.1.4 # 用于运行代码生成

然后,运行flutter pub get来安装这些依赖项。接下来,你需要设置MobX的代码生成。在你的项目根目录下创建一个build.yaml文件,内容如下:

targets:
  $default:
    builders:
      mobx_codegen:
        enabled: true

然后,在项目根目录下运行flutter pub run build_runner build来生成必要的代码。

现在,让我们创建一个简单的Flutter应用,使用mobx_widget进行状态管理。

  1. 创建一个MobX Store

首先,创建一个名为counter_store.dart的文件,用于定义你的MobX store:

import 'package:mobx/mobx.dart';

part 'counter_store.g.dart';

class CounterStore = _CounterStore with _$CounterStore;

abstract class _CounterStore with Store {
  int _count = 0;

  @observable
  int get count => _count;

  @action
  void increment() {
    _count++;
  }
}

注意,这里使用了partpart of语法来配合mobx_codegen生成代码。

  1. 使用MobX Store在Flutter中管理状态

接下来,在你的主应用文件(例如main.dart)中,使用生成的CounterStore来管理状态:

import 'package:flutter/material.dart';
import 'package:mobx_flutter/mobx_flutter.dart';
import 'counter_store.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final CounterStore counterStore = CounterStore();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter MobX Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Observer(
        builder: (_) => MyHomePage(store: counterStore),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final CounterStore store;

  MyHomePage({required this.store});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter MobX Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '${store.count}',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          store.increment();
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

在这个示例中,MyApp组件创建了一个CounterStore实例,并使用Observer widget来包装MyHomePageObserver widget监听其子组件中的任何MobX observable变化,并在变化时重新构建UI。

MyHomePage组件显示当前的计数器值,并提供一个按钮来增加计数器的值。当按钮被点击时,store.increment()方法被调用,这会导致store.count的值增加,从而触发UI的重新构建。

以上就是一个使用mobx_widget进行状态管理的简单Flutter应用的示例。希望这对你有所帮助!

回到顶部