BloomWidget class abstract
A reactive widget that dynamically and explicitly tracks all Bloom dependencies declared via BloomVia within build.
Seamlessly connects Flutter widget rebuild cycles with Bloom's 2-Phase LPDAG engine using 1-pass zero-allocation epoch diffing. Rather than managing manual streams, listeners, or ChangeNotifier subscriptions, dependencies are registered dynamically and explicitly via the injected BloomVia parameter in build.
System Architectural Flow
[ Upstream Bloom<T> Mutation ]
│
│ (Phase 1: 0-Compute Push-Dirty Invalidation)
▼
[ RawComputedTerminal<Widget>.onInvalidated: markNeedsBuild() ]
│
│ (Flutter Engine Frame Pipeline Scheduling)
▼
[ BloomElement.rebuild() -> performRebuild() ]
│
│ (Phase 2: Lazy-Pull Evaluation via terminal.data)
▼
┌────────────────────────────────────────────────────────────┐
│ If Clean: Returns cached Widget in O(1) (0-Compute) │
│ If Dirty: Evaluates BloomWidget.build(context, via) │
└────────────────────────────────────────────────────────────┘
Key Invariants & Architectural Benefits
- 0-Compute Reactive Memoization: When upstream state triggers frame invalidation but
dependencies resolve to clean (e.g. unchanged distinct intermediates),
terminal.datareturns the cached widget in $O(1)$ without re-evaluating build. (Note: Ancestor widget rebuilds pass new widget instances through Element.update, which re-evaluates build to honor updated widget parameters; useconstorcomposed.childfor ancestor isolation). - Zero Heap Overhead in Hot Path: Dynamic edge tracking utilizes 1-pass zero-allocation epoch stamping, avoiding intermediate list allocations during rebuilds.
- Dormancy Garbage Collection: When the widget unmounts, all active graph subscriptions detach synchronously via RawTerminal.deactivate.
- No Stateful Mutators: BloomWidget is intentionally immutable and declarative. Never mutate state synchronously inside build.
Warning (Anti-Pattern Prevention):
- Do NOT read untracked values directly without wrapping in
via(...), as untracked reads will not trigger widget rebuilds when state changes. - Do NOT mutate reactive state inside build, as this triggers reentrancy loops and violates Flutter's rendering contract.
BAD:
// [Anti-Pattern] Reading untracked directly bypasses dependency registration
class BadCounterWidget extends BloomWidget {
BadCounterWidget(this.countBloom, {super.key});
final Bloom<int> countBloom;
@override
Widget build(BuildContext context, BloomVia via) {
return Text('Count: ${untracked(countBloom)}'); // NEVER rebuilds!
}
}
GOOD:
// [Recommended] Explicitly observe dependencies via BloomVia
class GoodCounterWidget extends BloomWidget {
GoodCounterWidget(this.countBloom, {super.key});
final Bloom<int> countBloom;
@override
Widget build(BuildContext context, BloomVia via) {
return Text('Count: ${via(countBloom)}'); // Dynamically tracked
}
}
Examples
// Pure reactive state node:
final counter = blooming(0);
class CounterPage extends StatelessWidget {
const CounterPage({super.key});
@override
Widget build(BuildContext context) {
return CounterView(counterBloom: counter.bloom);
}
}
class CounterView extends BloomWidget {
const CounterView({required this.counterBloom, super.key});
final Bloom<int> counterBloom;
@override
Widget build(BuildContext context, BloomVia via) {
return Text('Count: ${via(counterBloom)}');
}
}
- Inheritance
-
- Object
- DiagnosticableTree
- Widget
- BloomWidget
- Implementers
Constructors
- BloomWidget({Key? key})
-
Initializes a BloomWidget with an optional
key.const
Properties
Methods
-
build(
BuildContext context, BloomVia via) → Widget - Describes the part of the user interface represented by this widget, with explicit BloomVia tracking.
-
createElement(
) → BloomElement -
Inflates this configuration to a concrete instance.
override
-
debugDescribeChildren(
) → List< DiagnosticsNode> -
Returns a list of DiagnosticsNode objects describing this node's
children.
inherited
-
debugFillProperties(
DiagnosticPropertiesBuilder properties) → void -
Add additional properties associated with the node.
inherited
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toDiagnosticsNode(
{String? name, DiagnosticsTreeStyle? style}) → DiagnosticsNode -
Returns a debug representation of the object that is used by debugging
tools and by DiagnosticsNode.toStringDeep.
inherited
-
toString(
{DiagnosticLevel minLevel = DiagnosticLevel.info}) → String -
A string representation of this object.
inherited
-
toStringDeep(
{String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug, int wrapWidth = 65}) → String -
Returns a string representation of this node and its descendants.
inherited
-
toStringShallow(
{String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) → String -
Returns a one-line detailed description of the object.
inherited
-
toStringShort(
) → String -
A short, textual description of this widget.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited