BloomFlutterExtension<T> extension
Extensions on a single Bloom providing the build and listen functor entry points.
Canonical Invocation & Cascade Hierarchy
bloom
├── .build ((context, data) => ...) [Declarative UI Rendering]
│ ├── .child ((context, data, child) => ..., child: W)
│ └── .children ((context, data, children) => ..., children: [...])
│
└── .listen ((context, state) => ...) [0-Rebuild Side Effects]
├── .debounce (duration, (context, state) => ...)
└── .throttle (duration, (context, state) => ...)
Built using Dart extension types (extension type const), bloom.build and bloom.listen incur
zero runtime allocation overhead while providing a fully type-safe, fluent, and canonical API for
inline reactive UI composition and 0-rebuild side-effect dispatch.
2-Phase LPDAG & Terminal Invariant Architecture
Unlike composed which uses RawComputedTerminal for dynamic multi-dependency discovery,
bloom.build provisions a dedicated 1:1 RawBloomTerminal hosted inside an internal ComponentElement
(_InlineSingleBloomElement, etc.) mixing in _BloomTerminalElementMixin<T>.
System Architectural Flow
[ Upstream Bloom<T> Mutates ]
│
│ (Phase 1: 0-Compute Push-Dirty Invalidation)
▼
[ RawBloomTerminal<T>.onInvalidated: markNeedsBuild() ]
│
│ (Flutter Render Pipeline Scheduling)
▼
[ _InlineSingleBloomElement.build() ]
│
├─► .build() ──► Evaluates builder(context, untracked(bloom))
├─► .build.child() ──► If hasData: builder(..., child) | Else: returns child (fallback)
└─► .build.children ──► If hasData: builder(..., children) | Else: returns SizedBox.shrink()
Key Invariants & Architectural Benefits
- Zero-Copy Auto-Healing Gateway: Directly routes dirty invalidation pulses to Element.markNeedsBuild without allocating intermediate tracking collections.
- Empty/Error State Fallback: When BloomState.hasData is
false, builder variants with a staticchildparameter return the fallbackchild(or SizedBox.shrink for children), protecting against extraction exceptions during uninitialized states. - Subtree Isolation: Static subtrees passed via
childorchildrenare pre-constructed and bypass re-evaluation when the enclosing reactive element rebuilds. - Zero Runtime Allocation: Backed by
extension type const, dispatching directly to dedicated 1:1 elements.
Warning (Anti-Pattern Prevention):
- Avoid instantiating static child trees inside the builder closure, which forces them to rebuild on every emission.
Pass static subtrees to the
child:orchildren:parameter to isolate them from rebuilds. - When invoking
bloom.build((context, data) => ...), ensure this Bloom node contains valid data. If the target node is uninitialized or in an error state, extracting data throws BloomSnapshotExtractionException. Usebloom.build.childor BloomAsyncBuilder for safe uninitialized/asynchronous state handling.
BAD:
// [Anti-Pattern] Static icon/chart recreated on every emission
counterBloom.build(
(context, count) => Row(children: [Text('$count'), const HeavyChartWidget()]),
);
GOOD:
// [Recommended] Static subtree cached and passed via child parameter
counterBloom.build.child(
(context, count, child) => Row(children: [Text('$count'), child]),
child: const HeavyChartWidget(),
);
- on
-
- Bloom<
T>
- Bloom<
Properties
-
build
→ BloomBuildFunctor<
T> -
Available on Bloom<
Entry point for inline single-node reactive UI build functors (BloomBuildFunctor).T> , provided by the BloomFlutterExtension extensionno setter -
listen
→ BloomListenFunctor<
T> -
Available on Bloom<
Entry point for inline zero-rebuild side-effect listener functors (BloomListenFunctor).T> , provided by the BloomFlutterExtension extensionno setter