BlocSelector

fun <B : StateEmitter<S>, S : Any, V : Any> BlocSelector(bloc: B, selector: (state: S) -> V, content: @Composable (value: V) -> Unit)

A composable that derives a value from a StateEmitter's state and rebuilds content only when that derived value changes.

BlocSelector is the most targeted rebuild primitive in the Bloc library. Where BlocBuilder rebuilds on every emission and BlocBuilder with buildWhen rebuilds on approved transitions, BlocSelector projects the state down to a single V via a selector closure and uses equals equality to suppress redundant rebuilds.

Overview

// Only recomposes when isLoading flips — card list updates are ignored
BlocSelector(
bloc = lorcanaBloc,
selector = { it.isLoading },
) { isLoading ->
if (isLoading) CircularProgressIndicator()
}

Composing multiple selectors

Derive multiple fields at once with an Equatable data class:

data class PaginationStatus(
val isLoadingMore: Boolean,
val hasMorePages: Boolean,
val cardCount: Int,
)

BlocSelector(
bloc = lorcanaBloc,
selector = { state ->
PaginationStatus(
isLoadingMore = state.isLoadingMore,
hasMorePages = state.hasMorePages,
cardCount = state.cards.size,
)
},
) { status ->
PaginationFooter(status)
}

When to use BlocSelector

NeedUse
Full state, rebuild on every emissionBlocBuilder
Rebuild at discrete thresholdsBlocBuilder with buildWhen
Rebuild only when a derived value changesBlocSelector

Parameters

bloc

The StateEmitter to observe.

selector

A function that projects the full state down to a single V. Called on every emission; content recomposes only when the result changes under ==. Ensure V has a correct equals implementation.

content

A composable receiving the derived value. The closure receives V, not the full state, preventing accidental subscriptions to other fields.


fun <B : StateEmitter<S>, S : Any, V : Any> BlocSelector(blocClass: KClass<B>, selector: (state: S) -> V, content: @Composable (value: V) -> Unit)

Overload that resolves the bloc from BlocRegistry by KClass.

BlocSelector(
blocClass = LorcanaBloc::class,
selector = { it.isLoading },
) { isLoading ->
if (isLoading) CircularProgressIndicator()
}