RefreshableComputedIterableWrapper
A ComputedIterableWrapper wrapped in a RefreshIndicator. It takes a RefreshableComputedState whose value is an Iterable, adds pull-to-refresh, and keeps the four-way loading / failure / empty / non-empty branching.
class InboxView extends HookWidget {
const InboxView({super.key, required this.service});
final InboxService service;
Widget build(BuildContext context) {
final messagesState = useAutoComputedState(service.load);
// RefreshableComputedListWrapper<Message> is the List<Message> shorthand for this.
return RefreshableComputedIterableWrapper<List<Message>>(
state: messagesState,
inProgressBuilder: (context) => const Center(child: CircularProgressIndicator()),
failedBuilder: (context) => const Center(child: Text('Could not load messages')),
emptyBuilder: (context) => const Center(child: Text('Inbox zero')),
builder: (context, messages) => ListView(
children: [for (final message in messages) Text(message.text)],
),
);
}
}
Constructor
RefreshableComputedIterableWrapper<I extends Iterable<dynamic>>({
Key? key,
required RefreshableComputedState<I> state,
required Widget Function(BuildContext) inProgressBuilder,
required Widget Function(BuildContext) failedBuilder,
required Widget Function(BuildContext) emptyBuilder,
required Widget Function(BuildContext, I) builder,
bool keepInProgress = false,
});
typedef RefreshableComputedListWrapper<E> = RefreshableComputedIterableWrapper<List<E>>;
state- aRefreshableComputedState<I>whereIis anIterable(usually aList<T>).inProgressBuilder/failedBuilder/emptyBuilder/builder/keepInProgress- identical toComputedIterableWrapper.
RefreshableComputedListWrapper<E> is a shorthand for the common List<E> case, so the type argument reads <Message> instead of <List<Message>>:
class InboxViewWithAlias extends HookWidget {
const InboxViewWithAlias({super.key, required this.service});
final InboxService service;
Widget build(BuildContext context) {
final messagesState = useAutoComputedState(service.load);
// Same widget, less noise: the List<E> type argument is implied.
return RefreshableComputedListWrapper<Message>(
state: messagesState,
inProgressBuilder: (context) => const Center(child: CircularProgressIndicator()),
failedBuilder: (context) => const Center(child: Text('Could not load messages')),
emptyBuilder: (context) => const Center(child: Text('Inbox zero')),
builder: (context, messages) => ListView(
children: [for (final message in messages) Text(message.text)],
),
);
}
}
Use cases
- A list screen that should support pull-to-refresh and has a meaningful empty state - an inbox with "Inbox zero", a non-paged search with "No matches". This is the collection counterpart of
RefreshableComputedStateWrapper. - Prefer the
RefreshableComputedListWrapper<E>alias forList<E>values; it is the same widget with less type noise.
When the list is paged rather than loaded whole, reach for PaginatedComputedStateWrapper instead - it adds load-more-on-scroll, which this widget does not.
Caveats
-
buildermust return a scrollable, for the same reason asRefreshableComputedStateWrapper: theRefreshIndicatorneeds a scrolling child to arm the pull. The empty, loading, and failure builders are made scroll-fillable by the wrapper, so an empty state can still be pulled to refresh. -
This wrapper refreshes the whole computation; it does not paginate. There is no
loadMore, no cursor. For endless lists usePaginatedComputedStateWrapper. -
All
ComputedIterableWrappersemantics carry over: emptiness isIterable.isEmptyon the ready value,failedBuildergets no error, andnotInitializedrenders as loading.
See also
- ComputedIterableWrapper - the non-refreshable base with the same four builders
- RefreshableComputedStateWrapper - the single-value refreshable wrapper
- PaginatedComputedStateWrapper - for paged lists with load-more-on-scroll
- useAutoComputedState - returns the
RefreshableComputedStatethis widget renders