data_state 0.2.7 copy "data_state: ^0.2.7" to clipboard
data_state: ^0.2.7 copied to clipboard

outdated

A practical alternative to the AsyncSnapshot API

data_state #

tests pub.dev license

Easily produce and consume loading/error/data states in your application.

DataState is a StateNotifier-based alternative to AsyncSnapshot.

  • Produce events: notifier API
  • Consume events: notifier API & stream API

👩🏾‍💻 Usage #

Consuming state #

Flutter example:

(Note: This example depends on flutter_data_state which is a separate package)

@override
Widget build(BuildContext context) {
  return DataStateBuilder<List<Post>>(
    notifier: repo.watchPosts(),
    builder: (context, state, _) {
      return Column(
        children: [
          if (state.isLoading)
            CircularProgressIndicator(),
          if (state.hasException)
            ExceptionWidget(state.exception),
          if (state.hasModel)
            ShowPost(state.model),
        ],
      );
    }
  );
}

The notifier also supports a reload function to restart a data loading cycle. It can be combined with a gesture detector or reloader widget:

Example 1:

GestureDetector(
  onTap: () => notifier.reload(), // will trigger a rebuild with isLoading = true
  child: _child,
)

Example 2:

body: EasyRefresh.builder(
  controller: _refreshController,
  onRefresh: () async {
    await notifier.reload();
    _refreshController.finishRefresh();
  },

Want to consume events via streams?

DataStateNotifier actually exposes an RxDart ValueStream:

@override
Widget build(BuildContext context) {
  final stream = repo.watchPosts().stream;
  return StreamBuilder<List<Post>>(
    initial: stream.value,
    stream: stream,
    builder: (context, snapshot) {
      // snapshot as usual
    }
  );
}

This is the anatomy of an immutable DataState object:

final state = DataState({
  T model,
  bool isLoading = false,
  Object exception,
  StackTrace stackTrace,
});

🎸 Producing state #

Example:

DataStateNotifier<List<Post>> watchPosts() {
  final notifier = DataStateNotifier<List<Post>>(
    DataState(model: getLocalPosts()),
    reload: (notifier) async {
      notifier.state = notifier.state.copyWith(isLoading: true);
      notifier.state = DataState(model: await loadPosts());
    },
    onError: (notifier, error, stackTrace) {
      notifier.state = notifier.state
          .copyWith(exception: error, stackTrace: stackTrace);
    },
  );

  // start cycle
  return notifier..reload();
}

The DataStateNotifier constructor takes:

  • state as the first positional argument
  • reload and onError as optional named arguments

⁉ FAQ #

Why is DataState not a freezed union? #

This would allow us to do the following destructuring:

state.when(
  data: (data) => Text(data),
  loading: () => const CircularProgressIndicator(),
  error: (error, stackTrace) => Text('Error $error'),
);

This turns out to be impractical in data-driven Flutter apps as there are cases where we need to render loading/error messages in addition to data – not instead of data.

Does DataStateNotifier depend on Flutter? #

No. It can used with pure Dart.

➕ Collaborating #

Please use Github to ask questions, open issues and send PRs. Thanks!

📝 License #

See LICENSE

1
likes
0
pub points
6%
popularity

Publisher

unverified uploader

A practical alternative to the AsyncSnapshot API

Repository (GitHub)
View/report issues

License

unknown (LICENSE)

Dependencies

async, freezed_annotation, rxdart, state_notifier

More

Packages that depend on data_state