Skip to content

onepub-dev/deferred_state

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DeferredState

DeferredState Provides a simple way of doing asynchronous initialisation for a StatefulWidget.

The StatefulWidget doesn't allow you to easily do async initialisation in [initState], resulting in the need for convulated methods to initialise state.

DeferredState provides a reliable and simple method of overcoming this problem by augmenting the [State] class with a [asyncInitState] method which behaves in a simiar manner to [initState] but allows async calls when coupled with the [DeferedBuilder].

There are two classes in the async_state package [DeferredState] and [DeferredBuilder].

To use [DeferredState] you derive your StatefulWidget's state from [DeferredState] instead of [State].

You then use [DeferredBuilder] in the State's [build] method so the builder isn't called until the async initialisation is complete. (DeferredBuilder wraps a FutureBuilder under the hood).

Custom UI

Whilst the UI is waiting or if an error occurs, DeferredBuilder provides a default [waitingBuilder] and [errorBuilder] implementation but you can roll your own (see below).

Sponsored by OnePub

Help support DeferredState by supporting OnePub, the private dart repository. OnePub allows you to privately share dart packages between your own projects or with colleagues. Try it for free and publish your first private package in seconds.

https://onepub.dev

Publish a private package in six commands:

dart pub global activate onepub
onepub login
flutter create -t package mypackage
cd mypackage
onepub pub private
dart pub publish

You can now add your private package to any app

onepub pub add mypackage

Example

The easist way to understand DeferredState is by an example.

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

class SchedulePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _SchedulPageState();
}

/// Derive from DeferredState rather than State
class _SchedulPageState extends DeferredState<SchedulePage> {
  /// requires async initialisation
  late final System system;
  /// requires sync initialisation so it can be disposed.
  late final TextEditingController _nameController;

  /// Items that are to be disposed must go in [initState]
  @override
  void initState() {
    super.initState();
    _nameController = TextEditingController();
  }

  /// Items that need to be initialised asychronously 
  /// go here. Make certain to [await] them, use 
  /// a [completer] if necessary.
  @override
  Future<void> asyncInitState() async {
    system = await DaoSystem().get();
  }

  @override
  void dispose() {
    _nameController.dispose();
    super.dispose();
  }

  Widget build(BuildContext context) {
    /// Waits for [asyncInitState] to complete and then calls
    /// the builder.
    return DeferredBuilder(this, builder: (context) => Text(system.name));
  }
}

class System {
  System(this.name);
  String name;
}

class DaoSystem {
  Future<System> get() async {
    /// get the system record from the db.
    return System('example');
  }
}

customising the waiting and error UI

The [DeferredBuilder] includes [waitingBuilder] and [errorBuilder] arguments to allow you to customise the UI during these phases but provides default builders for both.

If you don't like the default [waitingBuilder] and [errorBuilder] you can create you own version of DeferredBuilder with your own custom builders so you don't have to specify the [waitingBuilder] and [errorBuilder] at every call site.

The example includes [waitingBuilder] or [errorBuilder] as optional arguments to your [MyDeferredBuilder]. This isn't necessary unless you have call sites that need additional customisation (you may be better off creating multiple versions of [MyDeferredBuilder]). If you don't need this level of customisation then just delete the [waitingBuilder] and [errorBuilder] args that are passed to [MyDeferredBuilder].

/// Create your on [DeferredBuilder] to customise the
/// error and waiting builders without having to
/// specify them at every call site.
class MyDeferredBuilder extends StatelessWidget {
  MyDeferredBuilder(this.state,
      {required this.builder, this.waitingBuilder, this.errorBuilder});
  final DeferredState state;
  final WidgetBuilder builder;

  /// Include the waiting and error builders as arguments to
  /// [MyDeferredBuilder] if you might want to do further customisation at some
  /// call sites, otherwise delete these fields.
  final WaitingBuilder? waitingBuilder;
  final ErrorBuilder? errorBuilder;

  Widget build(BuildContext context) => DeferredBuilder(state,
      /// Customise the waiting message here
      waitingBuilder: (c => Center(child: Text('waiting')), here
      /// Customise the error message here.
      errorBuilder: (context, error) => Center(child: Text(error.toString())),
      builder: (context) => builder(context));
}

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages