Skip to content

Performance

Minimizing Rebuilds

  • The builder only re-executes when the ref or computed values it reads change.
  • Combined with ComputedBuilder or splitting into smaller widgets, you can further narrow the rebuild scope.

Performance Optimization Implementation

All reactive widgets (ComputedBuilder, CompositionWidget, CompositionBuilder) have adopted optimized rebuild mechanisms:

ComputedBuilder Optimization:

Uses a custom Element implementation to provide optimal performance:

  • Lower Latency: 15-25% reduction in single-update latency (for simple widgets)
  • Less Memory: ~56 bytes reduction per instance (~15%)
  • Direct Rebuild: Uses markNeedsBuild() instead of setState(), avoiding microtask scheduling overhead
  • Predictable Batching: More consistent batch behavior for synchronous updates

Technical details:

  • Removes scheduleMicrotask overhead (saves ~200-500 CPU cycles per update)
  • Removes setState closure creation (saves ~30 CPU cycles)
  • No State object needed, reducing memory footprint and GC pressure

CompositionWidget and CompositionBuilder Optimization:

Uses direct markNeedsBuild() calls instead of setState():

  • Reduced Overhead: Saves ~50 CPU cycles per reactive update
  • Faster Response: No need to create setState closure (saves ~30 cycles)
  • Fewer Checks: Avoids setState debug assertions (saves ~15 cycles)
  • Overall Improvement: 5-10% performance improvement for reactive updates

All optimizations maintain API backward compatibility, requiring no changes to existing code.

Batch Updates

  • Multiple .value = ... operations are batched within the same microtask, avoiding redundant rebuilds.
  • If you need to immediately see intermediate states, you can use await Future.microtask((){}) to force update segmentation.

Best Practices

  • Use computed to cache expensive calculations, such as sorting, filtering, or statistics.
  • Only read necessary refs in the builder; other data can be passed through const widgets or split into child widgets.
  • Use provide / inject to pass Ref instead of directly passing large objects, ensuring only actual consumers rebuild.

Monitoring and Debugging

  • Use watchEffect to temporarily observe dependencies, combined with debugPrint to confirm which values trigger updates.
  • If state becomes inconsistent after Hot Reload, check whether the ref declaration order has been changed.

Further Reading

Released under the MIT License.