ComputedIterableWrapper
A ComputedStateWrapper for a ComputedState whose value is an Iterable. It adds a fourth branch - an emptyBuilder shown when the computation succeeds but returns no items - so loading, failure, empty, and non-empty each get their own builder.
class ContactsView extends HookWidget {
const ContactsView({super.key, required this.service});
final ContactService service;
Widget build(BuildContext context) {
final contactsState = useAutoComputedState(service.loadAll);
return ComputedIterableWrapper<List<Contact>>(
state: contactsState,
inProgressBuilder: (context) => const Center(child: CircularProgressIndicator()),
failedBuilder: (context) => const Center(child: Text('Could not load contacts')),
emptyBuilder: (context) => const Center(child: Text('No contacts yet')), // <- ready but empty
builder: (context, contacts) => ListView(
children: [for (final contact in contacts) Text(contact.name)],
),
);
}
}
Constructor
ComputedIterableWrapper<I extends Iterable<dynamic>>({
Key? key,
required ComputedState<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,
});
state- aComputedState<I>whereIis someIterable(typically aList<T>).inProgressBuilder/failedBuilder- loading and failure UI, same asComputedStateWrapper.emptyBuilder- shown when the value is ready butvalue.isEmpty.builder- shown when the value is ready and non-empty; receives the iterable.keepInProgress(falseby default) - keeps the previous value on screen while a new computation runs.
The type parameter is the iterable itself (List<Contact>), not its element. The loading, failure, and empty builders are wrapped to fill a scroll view if one is the parent.
Use cases
- Any list-backed screen where "loaded but empty" needs different UI from "still loading" - a contacts list with a "No contacts yet" placeholder, search results with a "No matches" state.
- Reach for this over
ComputedStateWrapperwhenever the value is a collection. Routing the empty case throughbuilderand checking.isEmptyinside it duplicates what this widget already does.
For a list that also needs pull-to-refresh, use RefreshableComputedIterableWrapper.
Caveats
-
Emptiness is decided by
Iterable.isEmptyon the ready value. A non-empty iterable always goes tobuilder, even if every item would later be filtered out at render time - the wrapper does not know about downstream filtering. -
The same loading/empty ambiguity as
ComputedStateWrapperapplies: anotInitializedstate rendersinProgressBuilder. WithkeepInProgress: true, a non-empty previous value is held during a reload; an empty result still routes toemptyBuilderonce ready. -
failedBuilderreceives no error object, same as the base wrapper. Readstate.valuedirectly when you need the exception.
See also
- ComputedStateWrapper - the base wrapper, for non-collection values
- RefreshableComputedIterableWrapper - the same wrapper with pull-to-refresh
- useAutoComputedState - the usual source of a list-valued computed state
- PaginatedComputedStateWrapper - for paged lists rather than a single computed list