fairy 1.0.0-rc.1
fairy: ^1.0.0-rc.1 copied to clipboard
A lightweight MVVM framework for Flutter with strongly-typed, reactive data binding state management library, Mainly focused on simplicity and ease of use.
1.0.0-rc.1 #
๐ Major Release Candidate #
This release represents a major milestone with significant API improvements, enhanced performance, and comprehensive testing.
โจ New Features #
UI Widgets API Enhancement
Bind.observer<TViewModel>: New factory constructor for automatic property tracking- Eliminates need for manual selectors when displaying multiple properties
- Automatically tracks all accessed properties and rebuilds only when they change
- Achieves great selective rebuild efficiency over other state management solutions
- 4-10% faster than competitors while maintaining perfect selectivity
Command.param<TViewModel, TParam>: New factory constructor for parameterized commands- Provides consistent API alongside
Command<TViewModel> - Simplifies parameterized command binding in UI
- Completes the "2 widgets" framework positioning
- Provides consistent API alongside
๐ Breaking Changes #
Removed Extensions
- BREAKING: Removed
ObservableObjectExtensionsfor creating properties/commands- Before (Properties):
final counter = observableProperty<int>(0); - After (Properties):
final counter = ObservableProperty<int>(0); - Before (Commands):
late final saveCommand = relayCommand(_save); - After (Commands):
late final saveCommand = RelayCommand(_save); - Reason: Direct type usage is clearer, more discoverable, and follows Dart conventions
- Migration: Replace all
observableProperty<T>()withObservableProperty<T>() - Migration: Replace all
computedProperty<T>()withComputedProperty<T>() - Migration: Replace all command helpers (
relayCommand,asyncRelayCommand, etc.) with direct constructors (RelayCommand,AsyncRelayCommand, etc.)
- Before (Properties):
Command Constructor Changes
- BREAKING: Removed
parentparameter from all command constructors- Before:
RelayCommand(execute, parent: this, canExecute: ...) - After:
RelayCommand(execute, canExecute: ...) - Reason: Auto-disposal makes parent tracking unnecessary
- Migration: Remove
parent: thisfrom all command instantiations
- Before:
๐ Performance Improvements #
Comprehensive benchmarks show significant performance achievements:
- ๐ฅ Memory Management: Highly optimized cleanup and disposal system
- ๐ฅ Selective Rebuilds: Exceptional performance with explicit
Bindselectors - ๐ฅ Auto-tracking Performance:
Bind.observerdelivers superior speed while maintaining perfect selectivity - Unique Achievement: 100% rebuild efficiency with
Bind.observer- only rebuilds when accessed properties change
๐ Documentation Improvements #
- Updated all examples to use direct type constructors
- Added comprehensive
Bind.observerusage examples - Added
Command.paramexamples throughout documentation - "2 widgets" framework (Learn just
BindandCommand) - Enhanced best practices section with memory leak warnings
- Added benchmark results to main README
๐งช Testing #
- 344 tests passing (up from 299)
- Added comprehensive tests for new
Bind.observerfunctionality - Added tests for
Command.paramfactory constructor - All existing functionality validated with updated API
๐ฆ What's Next #
The 1.0.0 stable release is planned after community feedback on this RC. Please report any issues or suggestions!
0.5.0+2 #
- Improved documentation and fixed minor typos.
0.5.0+1 #
- Improved documentation and fixed minor typos.
0.5.0 #
Initial release of Fairy - A lightweight MVVM framework for Flutter.
Features #
Core Primitives
- ObservableObject: Base ViewModel class with clean MVVM API
onPropertyChanged()for manual notificationspropertyChanged(listener)method returning disposer functionsetProperty<T>()helper for batch updates with change detection- Auto-disposal: Properties created during construction are automatically disposed
- ObservableProperty: Strongly-typed reactive properties
- Automatic change notifications with custom equality support
propertyChanged(listener)for subscribing to property changes (returns disposer)- Auto-disposal when parent ObservableObject is disposed
- ComputedProperty: Derived properties with automatic dependency tracking
- Read-only computed values based on other properties
- Automatic updates when dependencies change
- Auto-disposal when parent ObservableObject is disposed
Commands
- RelayCommand: Synchronous commands with optional
canExecutevalidation - AsyncRelayCommand: Asynchronous commands with automatic
isRunningstate - RelayCommandWithParam: Parameterized commands for actions requiring input
- AsyncRelayCommandWithParam: Async parameterized commands
- All commands use named parameters:
execute:,canExecute:,parent: notifyCanExecuteChanged()method to re-evaluatecanExecuteconditionscanExecuteChanged(listener)method for subscribing tocanExecutechanges (returns disposer function)
Dependency Injection
- FairyLocator: Global singleton registry for app-wide services
registerSingleton<T>()for singleton registrationregisterFactory<T>()for factory registrationget<T>()for service resolutionunregister<T>()for cleanup
- FairyScope: Widget-scoped DI with automatic disposal
- Scoped ViewModels auto-disposed when widget tree is removed
- Supports both
createandinstanceparameters
- Fairy (ViewModelLocator): Unified resolution checking scope โ global โ exception
Fairy.of<T>(context): Idiomatic Flutter API for resolving ViewModels (similar toProvider.of,Theme.of)Fairy.maybeOf<T>(context): Optional resolution returningnullif not found
UI Binding
- Bind<TViewModel, TValue>: Automatic one-way/two-way binding detection
- Returns
ObservableProperty<T>โ two-way binding withupdatecallback - Returns raw
Tโ one-way binding (read-only) - Type-safe selector/builder contracts
- Returns
- Command: Command binding with automatic
canExecutereactivity - CommandWithParam<TViewModel, TParam>: Parameterized command binding
Auto-Disposal System
- Parent Parameter: Properties, commands, and computed properties accept optional
parentparameter- Pass
parent: thisin constructor to enable automatic disposal - Children are registered with parent and disposed automatically
- Debug warnings shown when parent is not provided
- Nested ObservableObject instances must be disposed manually
- Pass
Memory Management #
- Auto-disposal: ObservableProperty, ComputedProperty, and Commands automatically disposed when
parentparameter is provided - Nested ViewModels Exception: Nested ObservableObject instances require manual disposal
- Manual Listeners: Always capture disposer from
propertyChanged()andcanExecuteChanged()calls to avoid memory leaks - Use
BindandCommandwidgets for UI (automatic lifecycle management)
Best Practices #
- โ ๏ธ Memory Leak Prevention: Always capture disposer from manual
propertyChanged()andcanExecuteChanged()calls - Pass
parent: thisto properties, commands, and computed properties for auto-disposal - Nested ViewModels require explicit manual disposal
- Call
command.notifyCanExecuteChanged()whencanExecutedependencies change - Use
command.canExecuteChanged(listener)to listen tocanExecutestate changes - Selectors must return stable property references
- Use
FairyScopefor page-level ViewModels (handles disposal automatically) - Use named parameters for commands:
execute:,canExecute:,parent:
Documentation #
- Comprehensive README with quick start guide
- Auto-disposal explanation and migration patterns
- Complete API reference with examples
- Example app demonstrating MVVM patterns
Testing #
- Comprehensive unit and widget tests with 100% passing rate
- Tests cover all core primitives, DI patterns, UI bindings, and auto-disposal
- Test structure mirrors library organization