Introduction of fetching_state package

0
928
flutter

This package is inspired by the Union type provided by freezed package. But sometimes, it could be too complicating or you join a legacy project or a team project that it’s not ready to migrate to that package.

Fetching_state for simplification

Most of the time, in your app, you have to fetch remote data that would take a while after sending the request until obtaining the data. That is where and when you want to display something like a Loading Indicator and then either a successful fetched content or error content.

Normally, we would you some boolean state to indicate whether data is being fetched, another state for notifying error. Follow by some if else statements.

That’s why I create the package fetching_state. This package helps you to handle fetching state easier and cleaner, get rid of those if else statements when data is fetching, finished fetching, or error on fetching even an init state that lives before those ones.

Features of fetching_state package

  • Get rid of if else statements in UI
  • Decide what to display when fetching remote data in 4 states [initloading,doneerror]
  • Option to pass the data or error objects in onDone and onError

Usage of fetching_state

In this example, for the sake of simplification, we use a stateful widget. But this package and be used with any state management solution.

create a fetching state with init state _fetching = FetchingState.init();

and then, depending on the state of your app we can set it to appropriate status as follow

_fetching = FetchingState.loading();

_fetching = FetchingState.done()

_fetching = FetchingState.error()

In the build method, you can use when or whenOrElse method to build the corresponding widget.

For more options, you can pass data into FetchingState.done({T? data}) and FetchingState.error({E? error}). These data later can be accessed in: R Function(T? data) onDone, R Function(E? error) onError when you declare your when method as in the example.

return _fetching.when(
                    onInit: () => const Text(
                      'INIT',
                      style: TextStyle(color: Colors.blue),
                    ),
                    onDone: (text) => Text(
                      text!,
                      style: const TextStyle(color: Colors.green),
                    ),
                    onError: (error) => Text(
                      error!,
                      style: const TextStyle(color: Colors.red),
                    ),
                    onLoading: () => const CircularProgressIndicator(),
                  );

for more details, please visit: https://pub.dev/packages/fetching_state

Full Example

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

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

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Fetchin State Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        textTheme: const TextTheme(
          bodyText2: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
      home: const Example(),
    );
  }
}

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

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

class _ExampleState extends State<Example> {
  late FetchingState<String, String> _fetching;
  @override
  void initState() {
    _fetching = FetchingState.init();
    super.initState();
  }

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

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

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

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Center(
              child: Builder(
                builder: (context) {
                  return _fetching.when(
                    onInit: () => const Text(
                      'INIT',
                      style: TextStyle(color: Colors.blue),
                    ),
                    onDone: (text) => Text(
                      text!,
                      style: const TextStyle(color: Colors.green),
                    ),
                    onError: (error) => Text(
                      error!,
                      style: const TextStyle(color: Colors.red),
                    ),
                    onLoading: () => const CircularProgressIndicator(),
                  );
                },
              ),
            ),
            const SizedBox(
              height: 40,
            ),
            ElevatedButton(
              onPressed: getDone,
              child: const Text('Done'),
            ),
            ElevatedButton(
              onPressed: getError,
              child: const Text('Error'),
            ),
            ElevatedButton(
              onPressed: getInit,
              child: const Text('Init'),
            ),
          ],
        ),
      ),
    );
  }
}

LEAVE A REPLY

Please enter your comment!
Please enter your name here