Flutter响应式数据管理插件reactive_data_manager的使用

Flutter响应式数据管理插件reactive_data_manager的使用

一个为Flutter提供的强大响应式数据管理系统,内置缓存、乐观更新和错误处理功能。

特性

  • 🔄 响应式数据流
  • 💾 自动缓存
  • ⚡ 乐观更新
  • 🔍 数据过滤
  • ❌ 错误处理
  • 🧹 自动资源清理

安装

pubspec.yaml文件中添加以下依赖:

dependencies:
    reactive_data_manager: ^1.0.0

基本用法

// 创建管理器实例
final userManager = ReactiveDataManager<int, User>(
    fetcher: (id) => fetchUserFromApi(id),
    updater: (id, user) => updateUserInApi(id, user),
);

// 获取数据流
Stream<User?> userStream = userManager.getStream(userId);

// 获取或刷新数据
User user = await userManager.getData(userId);

// 强制刷新
User freshUser = await userManager.getData(userId, forceRefresh: true);

// 更新数据
await userManager.updateData(userId, updatedUser);

高级用法

带有数据过滤

ReactiveDataManager<String, Data>(
    fetcher: fetchData,
    updater: updateData,
    fetchFilter: (key, data) {
        // 过滤获取的数据
        return data.isValid ? data : null;
    },
    updateFilter: (key, result) {
        // 过滤更新结果
        return result.success ? result.data : null;
    },
);

在Flutter小部件中使用

StreamBuilder<User?>(
    stream: userManager.getStream(userId),
    builder: (context, snapshot) {
        if (snapshot.hasError) {
            return ErrorWidget(snapshot.error!);
        }
        
        if (!snapshot.hasData) {
            return LoadingWidget();
        }
        
        return UserWidget(user: snapshot.data!);
    },
);

清理

当不再需要管理器时,记得释放它:

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

完整示例代码

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

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

// 示例数据类
class User {
  final int id;
  final String name;
  final int age;

  User({required this.id, required this.name, required this.age});

  User copyWith({String? name, int? age}) {
    return User(
      id: id,
      name: name ?? this.name,
      age: age ?? this.age,
    );
  }

  [@override](/user/override)
  String toString() => 'User(id: $id, name: $name, age: $age)';
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
        useMaterial3: true,
      ),
      home: const ReactiveShowcase(),
    );
  }
}

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

  [@override](/user/override)
  State<ReactiveShowcase> createState() => _ReactiveShowcaseState();
}

class _ReactiveShowcaseState extends State<ReactiveShowcase> {
  late final ReactiveDataManager<int, User> _userManager;
  final _nameController = TextEditingController();
  final List<int> userIds = List.generate(100, (id) => id);

  [@override](/user/override)
  void initState() {
    super.initState();
    _userManager = ReactiveDataManager<int, User>(
      fetcher: _fetchUser,
      updater: _updateUser,
    );

    // 预取所有用户
    for (final id in userIds) {
      _userManager.getData(id);
    }
  }

  Future<User> _fetchUser(int id) async {
    await Future.delayed(const Duration(seconds: 1));
    return User(
      id: id,
      name: 'User $id',
      age: 20 + id,
    );
  }

  Future<User> _updateUser(int id, User user) async {
    await Future.delayed(const Duration(milliseconds: 500));
    return user;
  }

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('示例')),
      body: ListView.builder(
        itemCount: userIds.length,
        itemBuilder: (context, index) {
          final userId = userIds[index];
          return Card(
            margin: const EdgeInsets.all(8),
            child: StreamBuilder<User?>(
              stream: _userManager.getStream(userId),
              builder: (context, snapshot) {
                if (snapshot.hasError) {
                  return ListTile(
                    title: Text('错误: ${snapshot.error}'),
                    trailing: IconButton(
                      icon: const Icon(Icons.refresh),
                      onPressed: () =>
                          _userManager.getData(userId, forceRefresh: true),
                    ),
                  );
                }

                if (!snapshot.hasData) {
                  return const ListTile(
                    title: Center(child: CircularProgressIndicator()),
                  );
                }

                final user = snapshot.data!;
                return ListTile(
                  title: Text('姓名: ${user.name}'),
                  subtitle: Text('年龄: ${user.age}'),
                  trailing: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      IconButton(
                        icon: const Icon(Icons.edit),
                        onPressed: () => _showEditDialog(user),
                      ),
                      IconButton(
                        icon: const Icon(Icons.refresh),
                        onPressed: () =>
                            _userManager.getData(userId, forceRefresh: true),
                      ),
                    ],
                  ),
                );
              },
            ),
          );
        },
      ),
    );
  }

  Future<void> _showEditDialog(User user) async {
    _nameController.text = user.name;
    return showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('编辑用户 ${user.id}'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            TextField(
              controller: _nameController,
              decoration: const InputDecoration(labelText: '姓名'),
            ),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('取消'),
          ),
          TextButton(
            onPressed: () {
              final updatedUser = user.copyWith(name: _nameController.text);
              _userManager.updateData(user.id, updatedUser);
              Navigator.pop(context);
            },
            child: const Text('保存'),
          ),
        ],
      ),
    );
  }
}

更多关于Flutter响应式数据管理插件reactive_data_manager的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter响应式数据管理插件reactive_data_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


reactive_data_manager 是 Flutter 中用于管理响应式数据的插件。它可以帮助开发者更方便地管理应用状态,并在数据变化时自动更新 UI。虽然你可能找不到一个名为 reactive_data_manager 的官方或广泛使用的插件,但 Flutter 中有许多类似的状态管理工具,例如 Provider, Riverpod, GetX 等。以下是一个假设的使用 reactive_data_manager 的示例,假设它的使用方式类似于这些状态管理工具。

1. 安装插件

首先,假设 reactive_data_manager 是一个有效的插件,你需要在 pubspec.yaml 文件中添加依赖:

dependencies:
  flutter:
    sdk: flutter
  reactive_data_manager: ^1.0.0  # 假设的版本号

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

2. 创建一个响应式数据管理器

假设 reactive_data_manager 提供了一个 ReactiveDataManager 类,你可以使用它来管理应用的状态。

import 'package:reactive_data_manager/reactive_data_manager.dart';

class CounterManager extends ReactiveDataManager<int> {
  CounterManager() : super(0);

  void increment() {
    value++;
  }

  void decrement() {
    value--;
  }
}

在这个例子中,CounterManager 继承自 ReactiveDataManager,并管理一个整数状态。

3. 在 UI 中使用响应式数据

假设 reactive_data_manager 提供了一个 ReactiveBuilder 小部件,可以在数据变化时自动重建 UI。

import 'package:flutter/material.dart';
import 'package:reactive_data_manager/reactive_data_manager.dart';
import 'counter_manager.dart';  // 假设的 CounterManager 类

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterScreen(),
    );
  }
}

class CounterScreen extends StatelessWidget {
  final CounterManager counterManager = CounterManager();

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Reactive Data Manager Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ReactiveBuilder(
              manager: counterManager,
              builder: (context, value) {
                return Text(
                  'Counter: $value',
                  style: Theme.of(context).textTheme.headline4,
                );
              },
            ),
            SizedBox(height: 20),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: () => counterManager.increment(),
                  child: Text('Increment'),
                ),
                SizedBox(width: 20),
                ElevatedButton(
                  onPressed: () => counterManager.decrement(),
                  child: Text('Decrement'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}
回到顶部