Flutter状态管理工具插件use_state_utils的使用

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

Flutter状态管理工具插件use_state_utils的使用

UseStateMixin 简化了在 StatefulWidget 中管理 Flutter 资源(如 AnimationControllerStreamSubscriptionTimerValueNotifier)的过程。它通过自动管理这些资源的生命周期来减少样板代码。

特性

  • 生命周期管理:确保资源的正确创建和销毁。
  • 减少样板代码:减少管理动画、流、计时器和值通知器的代码量。
  • 易于使用:将常见任务简化为单个方法调用。
  • 可定制:轻松集成自定义可处置组件以混合生命周期。
  • 减少代码:编写更少的代码,提高效率。让我们为您处理资源的销毁。

可视示例

useNotifier

screenshot

usePeriodicTimer

screenshot

useStreamSubscription

screenshot

useAnimationController

screenshot

开始使用

要将此混入应用于您的 Flutter 应用程序,请遵循以下步骤:

安装

在您的 Flutter 项目中添加 use_state_utils,请将以下行添加到您的 pubspec.yaml 文件中:

dependencies:  
  use_state_utils: 

然后运行 flutter pub get 来安装该包。

使用示例

以下是一个使用 UseStateMixinAnimationController 的快速示例:

class _MyAnimatedWidgetState extends State<MyAnimatedWidget> with TickerProviderStateMixin, UseStateMixin<MyAnimatedWidget> {  
  late AnimationController _controller;  
  
  [@override](/user/override) 
  void initState() { 
    super.initState(); 
    _controller = useAnimationController(key: 'anim1', duration: const Duration(seconds: 2), vsync: this); 
    _controller.forward(); 
  }  
  
  [@override](/user/override) 
  Widget build(BuildContext context) { 
    return FadeTransition( 
      opacity: _controller, 
      child: const Center(child: Text('Hello, World!')), 
    ); 
  } 
}

API

useNotifier<V>

  • 描述:创建一个带有指定 durationvsyncAnimationController
  • 参数
    • key: String 键。
    • initialValue: V 动画的初始值。

useAnimationController

  • 描述:创建一个带有指定 durationvsyncAnimationController
  • 参数
    • key: String 键。
    • duration: Duration 动画的持续时间。
    • vsync: TickerProvider 控制器的同步器。

useStreamSubscription

  • 描述:管理一个 StreamSubscription
  • 参数
    • key: String 键。
    • stream: 订阅的流。
    • onData: 数据事件回调。

useTextEditingController

  • 描述:管理一个 StreamSubscription
  • 参数
    • key: String 键。
    • text: String? 初始值。

useTimerusePeriodicTimer

  • 描述:管理单次或周期性定时器。
  • 参数
    • key: String 键。
    • duration: Duration 定时器每次触发的时间间隔或直到定时器触发的时间。
    • callback: 定时器触发时执行的函数。

useCustomScene<R>

  • 描述:管理一个自定义可处置组件。
  • 参数
    • key: String 键。
    • createHandler: 创建 R 对象的函数。
    • disposeHandler: 在 UseStateScene 内部处置对象的回调。

完整示例

以下是一个完整的示例,展示了如何使用 UseStateMixin 来管理动画控制器、周期性定时器、流订阅等。

import 'package:flutter/material.dart';
import 'package/flutter/services.dart';
import 'dart:async';
import 'package:use_state_utils/use_state_utils.dart';
import 'package:rxdart/rxdart.dart';

void main() {
  UseStateConfig.debugPrintOnFailedDispose = true;
  UseStateConfig.debugPrintOnSuccessDispose = true;
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return const MaterialApp(
      localizationsDelegates: [
        DefaultMaterialLocalizations.delegate,
        DefaultWidgetsLocalizations.delegate,
      ],
      home: HomePage(), // Use DemoPage as the home widget
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  [@override](/user/override)
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  [@override](/user/override)
  void initState() {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
        systemNavigationBarColor: Colors.transparent,
        statusBarColor: Colors.blue.withOpacity(0.5)));
    SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
            child: ElevatedButton(
                onPressed: () {
                  Navigator.of(context).push(MaterialPageRoute(
                      builder: (context) => const DemoPage()));
                },
                child: const Text('Demo Page'))));
  }
}

class DemoPage extends StatefulWidget {
  const DemoPage({super.key});

  [@override](/user/override)
  State createState() => DemoPageState();
}

class DemoPageState extends State<DemoPage> with UseStateMixin<DemoPage>, TickerProviderStateMixin {
  late AnimationController _animationController;
  late Animation<Color?> _colorTween;
  late BehaviorSubject<int?> _streamController;
  int _counter = 0;

  [@override](/user/override)
  void initState() {
    super.initState();
    _animationController = useAnimationController(key: 'anim1', vsync: this);
    _colorTween = ColorTween(begin: Colors.cyan, end: Colors.deepOrange).animate(_animationController);

    usePeriodicTimer(
        key: 'timer1',
        callback: _handleTimer,
        duration: const Duration(seconds: 1));

    _streamController = BehaviorSubject.seeded(null);

    useStreamSubscription(
      key: 'stream1',
      stream: _streamController,
      onData: _handleStreamData,
    );
  }

  void _handleTimer(Timer timer) {
    setState(() {
      _counter++;
    });
  }

  void _handleStreamData(int? data) {
    if (data == null) return;
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Stream Alert'),
        content: Text('Stream sent: $data'),
        actions: [
          TextButton(
            child: const Text('OK'),
            onPressed: () => Navigator.of(context).pop(),
          ),
        ],
      ),
    );
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('UseStateMixin Demo'),
      ),
      body: AnimatedBuilder(
          animation: _colorTween,
          builder: (context, _) {
            return Material(
              color: _colorTween.value,
              key: const Key('background'),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  const Center(child: Text('Fade Transition')),
                  ElevatedButton(
                    onPressed: () {
                      if (_animationController.isCompleted) {
                        _animationController.reverse();
                      } else {
                        _animationController.forward();
                      }
                    },
                    child: const Text('Toggle Animation'),
                  ),
                  const SizedBox(height: 20),
                  Text('Timer count: $_counter'),
                  ElevatedButton(
                    onPressed: () => _streamController.add(99),
                    child: const Text('Send Stream Data'),
                  ),
                ],
              ),
            );
          }),
    );
  }
}

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

1 回复

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


当然,以下是一个关于如何在Flutter项目中使用use_state_utils插件的示例代码。use_state_utils是一个用于简化状态管理的Flutter插件,它提供了许多有用的钩子(Hooks)来管理应用状态。

首先,确保你已经在pubspec.yaml文件中添加了use_state_utils依赖:

dependencies:
  flutter:
    sdk: flutter
  use_state_utils: ^latest_version # 请替换为最新版本号

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

接下来,我们将创建一个简单的Flutter应用,演示如何使用use_state_utils中的一些钩子。

示例代码

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter useStateUtils Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends HookWidget {
  @override
  Widget build(BuildContext context) {
    // 使用 useCounter 钩子,它内部维护一个计数状态
    final counterState = useCounter(initialValue: 0);

    // 使用 useBoolean 钩子,它内部维护一个布尔状态
    final isSwitchOn = useBoolean(initialState: false);

    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter useStateUtils Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '${counterState.value}',
              style: Theme.of(context).textTheme.headline4,
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                counterState.increment();
              },
              child: Text('Increment'),
            ),
            SizedBox(height: 20),
            Text('Switch is ${isSwitchOn.value ? "ON" : "OFF"}'),
            SizedBox(height: 20),
            Switch(
              value: isSwitchOn.value,
              onChanged: (value) {
                isSwitchOn.setValue(value);
              },
            ),
          ],
        ),
      ),
    );
  }
}

// 假设 useCounter 是一个自定义钩子,定义如下:
// 这个钩子维护一个整数值,并提供增加和重置的方法
class UseCounterHook extends Hook<int, UseCounterState> {
  final int initialValue;

  UseCounterHook({required this.initialValue});

  @override
  UseCounterState createState() => UseCounterState(value: initialValue);
}

class UseCounterState {
  int value;

  UseCounterState({required this.value});

  void increment() {
    value++;
    notifyListeners();
  }

  void reset() {
    value = 0;
    notifyListeners();
  }
}

// useCounter 是一个方便的方法,用于在 HookWidget 中使用这个钩子
UseCounterState useCounter({required int initialValue}) {
  return use(UseCounterHook(initialValue: initialValue));
}

注意use_state_utils 插件本身可能并不包含useCounter钩子,这里我们为了演示目的自定义了一个UseCounterHook。在实际使用中,你可能需要查看use_state_utils的文档来了解它提供的具体钩子和用法。

在实际项目中,你可能会使用use_state_utils提供的钩子,比如useStateuseEffect等,这些钩子更加通用和强大。以下是一个使用useState的简单示例:

class MyHomePage extends HookWidget {
  @override
  Widget build(BuildContext context) {
    // 使用 useState 钩子,它内部维护一个状态和一个更新状态的函数
    final String text = useState('Hello, World!')[0];
    final void Function(String) setText = useState('Hello, World!')[1];

    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter useState Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(text),
            SizedBox(height: 20),
            TextField(
              onChanged: setText,
              decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Enter text',
              ),
            ),
          ],
        ),
      ),
    );
  }
}

在这个例子中,我们使用了useState钩子来管理一个文本字符串的状态,并在用户输入时更新这个状态。希望这些示例能帮助你理解如何在Flutter项目中使用use_state_utils插件进行状态管理。

回到顶部