Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

36 Commits

Repository files navigation

DISCONTINUED

This package has been integrated (and improved) into Flutter Data


data_state

testspub.devlicense

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

DataState is a StateNotifier-based alternative to AsyncSnapshot.

  • Produce events from DataStateNotifier, Future, Stream, RxDart ValueStream
  • Consume events through DataStateNotifier, Stream

👩🏾‍💻 Usage

Consuming state

Flutter example:

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

@overrideWidgetbuild(BuildContext context) {
returnDataStateBuilder<List<Post>>(
notifier: () => repo.watchPosts(),
builder: (context, state, notifier, _) {
returnColumn(
children: [
if (state.isLoading)
CircularProgressIndicator(),
if (state.hasException)
ExceptionWidget(state.exception),
if (state.hasModel)
ShowPost(state.model),
],
);
}
);
}

The notifier features a reload function, useful 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:

RefreshIndicator(
onRefresh: notifier.reload,
child: _child,
),

Future & Stream input support

This package exposes an extension on Future<T> Function() called asDataNotifier.

It allows to turn any future into a DataStateNotifier callback to leverage caching and reloading capabilities.

Example 1:

final notifier = (() => future).asDataNotifier;

Example 2:

final notifier = (() {
if (Random().nextInt(10) >4) {
returnFuture<String>.error('Error!');
}
returnFuture.delayed(
Duration(seconds:1),
() =>'HELLO RANDOM: ${Random().nextInt(100)}!',
);
}).asDataNotifier;

Same for Streams and ValueStreams:

final notifier = (() => stream).asDataNotifier;

Consuming streams

Want to consume events via streams?

DataStateNotifier actually exposes an RxDart ValueStream:

@overrideWidgetbuild(BuildContext context) {
final stream = repo.watchPosts().stream;
returnStreamBuilder<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);
try {
notifier.data =awaitloadPosts();
} catch (error, stackTrace) {
notifier.data = notifier.data.copyWith(exception: error, stackTrace: stackTrace);
}
},
);
// kick off cyclereturn 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: () =>constCircularProgressIndicator(),
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

About

Easily consume and produce loading/error/data states in your Flutter app

Resources

Stars

6 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages