Skip to main content

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 - a ComputedState<I> where I is some Iterable (typically a List<T>).
  • inProgressBuilder / failedBuilder - loading and failure UI, same as ComputedStateWrapper.
  • emptyBuilder - shown when the value is ready but value.isEmpty.
  • builder - shown when the value is ready and non-empty; receives the iterable.
  • keepInProgress (false by 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 ComputedStateWrapper whenever the value is a collection. Routing the empty case through builder and checking .isEmpty inside it duplicates what this widget already does.

For a list that also needs pull-to-refresh, use RefreshableComputedIterableWrapper.

Caveats

  • Emptiness is decided by Iterable.isEmpty on the ready value. A non-empty iterable always goes to builder, 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 ComputedStateWrapper applies: a notInitialized state renders inProgressBuilder. With keepInProgress: true, a non-empty previous value is held during a reload; an empty result still routes to emptyBuilder once ready.

  • failedBuilder receives no error object, same as the base wrapper. Read state.value directly when you need the exception.

See also