Flutter数据获取状态管理插件fetching_state的使用

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

Flutter数据获取状态管理插件fetching_state的使用

fetching_state 是一个小型的 Flutter 插件,帮助你轻松地处理基于远程数据获取状态的 UI 变化。本文将详细介绍如何安装、使用 fetching_state 插件,并提供一个完整的示例。

目录

  1. FetchingState
  2. LoadStatus
  3. LoadingState

特点

  • 减少 UI 中的 if else 语句:使 UI 代码更简洁。
  • 在四种状态下决定显示内容[init, loading, done, error, loadingMore]
  • 可传递数据或错误对象:在 onDoneonError 中使用。

入门指南

安装库

在你的 pubspec.yaml 文件中添加依赖:

dependencies:
  fetching_state:

然后在需要使用的地方导入库:

import 'package:fetching_state/fetching_state.dart';

使用方法

1. FetchingState

示例代码

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

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Fetching State FetchingStateExample',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        textTheme: const TextTheme(
          bodyText2: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
      home: const FetchingStateExample(),
    );
  }
}

class FetchingStateExample extends StatefulWidget {
  const FetchingStateExample({Key? key}) : super(key: key);

  @override
  _FetchingStateExampleState createState() => _FetchingStateExampleState();
}

class _FetchingStateExampleState extends State<FetchingStateExample> {
  late FetchingState<String?> _fetching;

  @override
  void initState() {
    _fetching = FetchingState.init(data: null);
    super.initState();
  }

  Future<void> getDone() async {
    setState(() {
      _fetching = _fetching.copyWhenLoading();
    });
    await Future.delayed(const Duration(milliseconds: 500));

    setState(() {
      _fetching = _fetching.copyWhenDone(data: 'DONE IN STATE');
    });
  }

  Future<void> loadMoreText() async {
    setState(() {
      _fetching = _fetching.copyWhenLoadingMore();
    });

    await Future.delayed(const Duration(milliseconds: 500));

    if (_fetching.data == null) {
      setState(() {
        _fetching = _fetching.copyWhenError(error: 'No current data');
      });
      return;
    }

    setState(() {
      _fetching = _fetching.copyWhenDone(data: '${_fetching.data} - extra text');
    });
  }

  Future<void> getError() async {
    setState(() {
      _fetching = _fetching.copyWhenLoadingMore();
    });
    await Future.delayed(const Duration(milliseconds: 500));

    setState(() {
      _fetching = _fetching.copyWhenError(error: 'Error IN STATE');
    });
  }

  Future<void> getInit() async {
    setState(() {
      _fetching = _fetching.copyWhenLoadingMore();
    });
    await Future.delayed(const Duration(milliseconds: 500));
    setState(() {
      _fetching = FetchingState.init(data: '');
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Spacer(),
            Center(
              child: Builder(
                builder: (context) {
                  return _fetching.when(
                    onInit: () => const Text(
                      'INIT',
                      style: TextStyle(color: Colors.blue),
                    ),
                    onDone: (text, isLoadingMore) => Text(
                      '${text ?? ''} ${isLoadingMore ? '....' : ''}',
                      style: const TextStyle(color: Colors.green),
                    ),
                    onError: (error) => Text(
                      error!.toString(),
                      style: const TextStyle(color: Colors.red),
                    ),
                    onLoading: () => const CircularProgressIndicator(),
                  );
                },
              ),
            ),
            const SizedBox(
              height: 40,
            ),
            ElevatedButton(
              onPressed: getDone,
              child: const Text('Done'),
            ),
            ElevatedButton(
              onPressed: loadMoreText,
              child: const Text('Load more text'),
            ),
            ElevatedButton(
              onPressed: getError,
              child: const Text('Error'),
            ),
            ElevatedButton(
              onPressed: getInit,
              child: const Text('Init'),
            ),
            const Spacer(),
            SizedBox(
              width: MediaQuery.of(context).size.width * .8,
              height: 60,
              child: TextButton(
                style: TextButton.styleFrom(
                  backgroundColor: Colors.blue,
                  foregroundColor: Colors.white,
                ),
                onPressed: () {
                  Navigator.of(context).push(
                    MaterialPageRoute(
                        builder: (context) => const LoadStatusExample()),
                  );
                },
                child: const Text('Load Status'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

2. LoadStatus

示例代码

class Counter with LoadStatusMixin {
  final int value;

  Counter(this.value);

  Counter copyWith({int? value}) {
    return Counter(value ?? this.value);
  }
}

class LoadStatusExample extends StatefulWidget {
  const LoadStatusExample({Key? key}) : super(key: key);

  @override
  State<LoadStatusExample> createState() => _LoadStatusExampleState();
}

class _LoadStatusExampleState extends State<LoadStatusExample> {
  Counter _counter = Counter(1);

  void increase() async {
    setState(() {
      _counter.setLoadStatusLoading();
    });

    await Future.delayed(const Duration(milliseconds: 500));
    setState(() {
      _counter = _counter.copyWith(value: _counter.value + 1);
      _counter.setLoadStatusDone();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Load Status Example'),
      ),
      body: Center(
        child: Column(
          children: [
            const Spacer(),
            Builder(
              builder: (context) {
                return _counter.whenOrElse(
                  onLoading: () => const CircularProgressIndicator(),
                  onDone: (_) => Text(_counter.value.toString()),
                  onInit: () => const Text('Init'),
                  onError: () => const Text('Error'),
                  orElse: () => const Text('Nothing'),
                );
              },
            ),
            const SizedBox(height: 10),
            ElevatedButton(
              onPressed: increase,
              child: const Text('Add'),
            ),
            const Spacer(),
          ],
        ),
      ),
    );
  }
}

3. LoadingState

LoadingState 类似于 FetchingState,但不需要数据对象。适用于只需要简单状态的情况。

欢迎反馈

如果你发现任何需要改进的地方或有新的功能需求,请在 GitHub 上创建一个 issue。

希望本文对你有所帮助!如果有任何问题,欢迎随时提问。


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

1 回复

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


当然,fetching_state 是一个用于 Flutter 的状态管理库,它主要用于处理数据获取过程中的状态管理,如加载中、加载成功、加载失败等。以下是如何在 Flutter 应用中使用 fetching_state 的一个简单示例。

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

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

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

接下来,我们来看一个具体的代码示例:

1. 创建一个数据模型

假设我们要获取一个用户列表,首先创建一个用户数据模型:

class User {
  final String name;
  final int age;

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

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      name: json['name'] as String,
      age: json['age'] as int,
    );
  }
}

2. 创建 FetchingState 提供者和数据获取逻辑

使用 fetching_state 来管理数据获取状态:

import 'package:flutter/material.dart';
import 'package:fetching_state/fetching_state.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;

class UserFetching extends FetchingState<List<User>, Exception> {
  @override
  Future<List<User>> fetchData() async {
    final response = await http.get(Uri.parse('https://api.example.com/users'));
    if (response.statusCode == 200) {
      final List<dynamic> body = jsonDecode(response.body);
      return body.map((dynamic item) => User.fromJson(item)).toList();
    } else {
      throw Exception('Failed to load users');
    }
  }
}

3. 使用 FetchingState 提供者在 UI 中显示数据

在你的 Flutter 应用中使用 UserFetching 提供者来显示用户列表:

void main() {
  runApp(
    FetchingProvider<List<User>, Exception>(
      create: () => UserFetching(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: UserListScreen(),
    );
  }
}

class UserListScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final fetchingState = FetchingState.of<List<User>, Exception>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('User List'),
      ),
      body: fetchingState.when(
        data: (users) {
          return ListView.builder(
            itemCount: users.length,
            itemBuilder: (context, index) {
              final user = users[index];
              return ListTile(
                title: Text(user.name),
                subtitle: Text('Age: ${user.age}'),
              );
            },
          );
        },
        loading: () => Center(child: CircularProgressIndicator()),
        error: (e, retry) {
          return Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text('Failed to load users'),
                TextButton(
                  onPressed: () => retry(),
                  child: Text('Retry'),
                ),
              ],
            ),
          );
        },
      ),
    );
  }
}

解释

  1. 数据模型User 类用于表示用户数据。
  2. FetchingState 提供者UserFetching 类扩展了 FetchingState 并实现了 fetchData 方法,用于从 API 获取用户数据。
  3. UI 显示UserListScreen 使用 FetchingProvider 包裹,并在 build 方法中使用 FetchingState.of 获取 fetchingState。然后,根据 fetchingState 的状态(加载中、数据、错误),显示相应的 UI。

这样,你就可以在 Flutter 应用中使用 fetching_state 来管理数据获取的状态了。

回到顶部