Flutter乐观更新策略插件use_optimistic的使用

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

Flutter乐观更新策略插件use_optimistic的使用

一个易于使用的hook,用于乐观地更新通用状态,并通过acceptacceptAsreject来异步或同步地解决它。

文档

  • 查看完整的示例以了解如何使用此hook管理整数状态。
  • GitHub仓库在此处。
  • 包在此处。

文档主要在包本身中通过doc-comments(即,在编辑器中悬停在包函数上会告诉您它们的作用)。首先,请查看上述完整的示例以开始使用。

简单用法

演示图像

初始化hook

final UseOptimistic<int> useOptimistic = UseOptimistic<int>(initialState: 0);

确保您的小部件监听到状态变化

[@override](/user/override)
void initState() {
  super.initState();
  useOptimistic.addListener(() => setState(() => debugPrint("state changed to: ${useOptimistic.state}")));
}

确保当您的小部件被销毁时释放hook

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

乐观地更新状态

TextButton(
  onPressed: () async {
    Resolver r = useOptimistic.fn(
      1, // 新值将传递给下面的函数
      todo: (currentState, newValue) => currentState + newValue, // 乐观更新函数
      undo: (currentState, oldValue) => currentState - oldValue, // 撤销函数
    );

    // 模拟API调用
    await Future.delayed(const Duration(seconds: 1));

    // 三种互斥的方式处理结果
    r.acceptAs(2); // 先撤销原始操作,再使用新值进行乐观更新
    r.accept(); // 接受原始的乐观更新
    r.reject(); // 拒绝原始的乐观更新并撤销原始操作
  },
  child: const Text("乐观地增加1"),
),

您可以多次调用useOptimistic.fn(...),每次传递不同的todoundo函数。这意味着您可以安全地一起调用多个独立的useOptimistic.fn(...)。但不意味着您可以有一个单一的fn像这样(伪代码):useOptimistic.fn( if x todo: () => {…} else todo: () => {…} ),其中todo/undo`函数根据条件渲染。

监听状态

Text("当前值: ${useOptimistic.state}"),

额外信息

  • 该包始终欢迎改进、建议和添加!
  • 我将尽快查看GitHub上的PR和Issue。

示例代码

import 'package:flutter/material.dart';
import 'package:use_optimistic/use_optimistic.dart'; // 导入包

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text("useOptimistic hook 整数示例 🔥"),
        ),
        body: const OptimisticUI(),
      ),
    );
  }
}

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

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

class OptimisticUIState extends State<OptimisticUI> {
  // 创建一个新的hook实例,设置其初始状态为0,并定义其类型为int
  final UseOptimistic<int> useOptimistic = UseOptimistic<int>(initialState: 0);

  [@override](/user/override)
  void initState() {
    super.initState();
    // 监听状态的变化并更新UI
    // 触发原始乐观更新和通过resolver.[someMethod]解决resolver
    // 一旦调用[clearQueue]和[reset]也会触发
    //
    // 这很重要,除非您调用此方法,否则您的UI不会响应状态更改!!!
    useOptimistic.addListener(() =>
        setState(() => debugPrint("状态更改为: ${useOptimistic.state}")));
  }

  [@override](/user/override)
  void dispose() {
    // 移除监听器以避免内存泄漏
    useOptimistic.dispose();
    super.dispose();
  }

  // 创建一个新的resolver来处理某些整数值的乐观更新
  Resolver<int> _addValue(int newValToFunctions) {
    return useOptimistic.fn(
      newValToFunctions, // 传递给下面函数的值
      todo: (currentState, newValue) =>
          currentState + newValue, // 乐观更新使用上面的值作为新的值
      undo: (currentState, oldValue) =>
          currentState - oldValue, // 撤销函数使用上面的值作为旧值
    );
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text("当前值: ${useOptimistic.state}"),
          const SizedBox(height: 40),
          // 测试乐观更新的按钮
          TextButton(
            onPressed: () async {
              final r = _addValue(1);
              await Future.delayed(
                  const Duration(seconds: 1)); // 模拟服务器响应
              // 假设服务器响应错误,所以我们想拒绝乐观更新
              r.accept();
              // 注意:多次调用r.[someMethod]没有效果;它只考虑第一次调用
              r.reject();
            },
            child: const Text("乐观地增加1(异步接受)"),
          ),
          // 使用新的.fn直接处理乐观更新
          TextButton(
            onPressed: () async {
              final r = useOptimistic.fn(
                5, // 传递给下面函数的值
                todo: (currentState, newValue) =>
                    currentState ~/ newValue, // 乐观更新
                undo: (currentState, oldValue) =>
                    currentState * oldValue, // 撤销函数(如所示,可以与[todo]完全相反)
              );
              await Future.delayed(
                  const Duration(seconds: 1)); // 模拟服务器响应
              r.reject();
            },
            child: const Text("乐观地喂入5到自定义函数(异步拒绝)"),
          ),
          TextButton(
            onPressed: () {
              useOptimistic
                  .fn(
                    1,
                    todo: (currentState, newValue) =>
                        currentState + newValue,
                    undo: (currentState, oldValue) =>
                        currentState - oldValue,
                  )
                  .accept(); // 再次,这会触发状态监听器两次 -> 一次为原始乐观更新,一次为resolver
            },
            child: const Text("乐观地增加1(同步接受)"),
          ),
          TextButton(
            onPressed: () async {
              final r = _addValue(1);
              await Future.delayed(
                  const Duration(seconds: 10)); // 模拟服务器响应
              // 假设服务器响应错误,所以我们想拒绝乐观更新
              r.reject();
            },
            child: const Text("乐观地增加1(异步拒绝)"),
          ),
          TextButton(
            onPressed: () async {
              final r = _addValue(1);
              await Future.delayed(
                  const Duration(seconds: 1)); // 模拟服务器响应
              // 假设服务器响应2,所以我们想将初始+1更改为+2
              r.acceptAs(2);
            },
            child: const Text("乐观地增加1(异步接受为2)"),
          ),
          TextButton(
            onPressed: () {
              // 示例:将状态设置为10
              useOptimistic.state = 10;
            },
            child: const Text("设置为10"),
          ),
          TextButton(
            // 清除待处理更新队列
            onPressed: () => useOptimistic.clearQueue(),
            child: const Text("清除队列"),
          ),
          TextButton(
            // 重置状态到初始状态
            onPressed: () => useOptimistic.reset(),
            child: const Text("重置"),
          ),
        ],
      ),
    );
  }
}

更多关于Flutter乐观更新策略插件use_optimistic的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter乐观更新策略插件use_optimistic的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter中使用use_optimistic插件来实现乐观更新策略的示例代码。use_optimistic插件允许你在等待异步操作(如网络请求)完成时,立即更新UI,从而提供即时的用户反馈。

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

dependencies:
  flutter:
    sdk: flutter
  use_optimistic: ^最新版本号  # 请替换为实际的最新版本号

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

以下是一个简单的示例,展示了如何使用use_optimistic来在Flutter中实现乐观更新:

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

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

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

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final optimisticProvider = OptimisticProvider<int>((ref) {
    // 初始值
    return 0;
  });

  void _incrementOptimistically() async {
    // 乐观地增加计数
    optimisticProvider.update((value) => value + 1);

    // 模拟一个异步操作,比如网络请求
    await Future.delayed(Duration(seconds: 2));

    // 确认更新(这里假设异步操作成功)
    optimisticProvider.confirm();
  }

  void _resetOptimistic() async {
    // 重置乐观更新(这里模拟异步操作失败的情况)
    optimisticProvider.reset();
  }

  @override
  Widget build(BuildContext context) {
    final count = optimisticProvider.watch(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('Optimistic Update Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$count',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementOptimistically,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
    );
  }
}

在这个示例中,我们创建了一个OptimisticProvider来管理一个整数值。_incrementOptimistically方法被调用时,我们首先乐观地增加计数(即不等待异步操作完成就更新UI),然后模拟一个异步操作(例如网络请求),并在操作完成后确认更新。如果异步操作失败,我们可以调用_resetOptimistic方法来重置乐观更新。

注意:

  • optimisticProvider.update方法用于乐观地更新状态。
  • optimisticProvider.confirm方法用于在异步操作成功后确认更新。
  • optimisticProvider.reset方法用于在异步操作失败时重置状态。

通过这种方式,你可以在Flutter中实现乐观更新策略,提高用户体验。

回到顶部