oref 2.4.2
oref: ^2.4.2 copied to clipboard
A reactive state management library for Flutter that adds magic to any Widget with signals, computed values, and effects powered by alien_signals.
2.4.2 #
- Fix context check in async data initialization
2.4.1 #
- Revert signal interface to use
call()
syntax
2.4.0 #
- Migrated to alien_signals 1.0.0
Widgets Lifecycle #
We've added experimental widget lifecycle features in this release:
import 'package:oref/experimental/lifecycle.dart';
onMounted(() {
print('Mounted');
});
onUpdated(() {
print('Updated');
});
Migration Guide #
All signal values ββcan be read using .value
:
import 'package:oref/oref.dart';
-import 'package:oref/async.dart';
-import 'package:oref/collections.dart';
final e = effect(context, () {
- onEffectStop({
+ onEffectDispose(() {
print('Effect disposed');
});
});
-e();
+e.dispose();
final scope = effectScope();
-scope();
+scope.dispose();
2.3.1 #
2.3.0 #
Status: Released (2025-09-25)
β¨ NEW FEATURES #
Effect Lifecycle.
We added the onEffectStop
lifecycle API, which allows you to do some cleanup work before the effect/efrect-scope is stopped.
final stop = effect(null, () {
print('Effect started');
onEffectStop(() {
print('Effect stopped');
});
});
stop(); // Stop the effect, and run the cleanup function
You typically don't need to manually call stop (similar to dispose in other frameworks) within the widget scope unless you want to clean up immediately. Automatic disposal is safe and won't prevent garbage collection from occurring because you didn't call stop; signal nodes aren't collected immediately. However, effects will automatically orphan them, so there's no need to worry about updating a signal without calling stop and causing an unintended effect to fire.
Finalizer #
Widget-level effects and scopes will now automatically clean up and orphan signal nodes when the BuildContext is discarded.
It only costs a few milliseconds after the GC, but frees you from worrying about resource release and the risk of accidentally updating signals causing effects to trigger.
2.2.0 #
Status: Released (2025-09-25)
π₯ BREAKING CHANGES #
Remove deprecated collections export
In previous versions, the structure has been standardized, and oref.dart
no longer exports collections by default. Starting with version 2.2, please import collections from collections.dart
.
+import 'package:oref/collections.dart';
β¨ NEW FEATURES #
Async data support
you can use useAsyncData to get access to data that resolves asynchronously.
Usage
final result = useAsyncData(context, () {
return oxy.get("https://example.com").then((e) => e.json());
});
Watch Params
You can listen to other signal sources directly in the handler to trigger data updates.
final page = signal(context, 1);
final result = useAsyncData(context, () async {
final res = await oxy.get('https://example.com?page=${page()}');
if (!res.ok) throw Exception('Failed to fetch data');
return res.json();
});
effect(context, () {
print("Status: ${result.status}");
if (result.status == AsyncStatus.error) {
print("Error: ${result.error}");
}
print("Data: ${result.data}");
});
// Get the 2 page after 5 seconds
Timer(const Duration(seconds: 5), () => page(2));
See the full demo: medz/oref - Async Data
π BUG FIXES #
- Fix widget effect not resetting memoization
2.1.2 #
Status: Released (2025-09-24)
π§ IMPROVEMENTS #
Reorganize library exports and file structure
Previously, ReactiveMap
, ReactiveList
, and ReactiveSet
were exported from oref.dart
. They are now exported from collections.dart
.
We plan to remove these exports from oref.dart
starting with version 2.2.0.
import 'package:oref/oref.dart';
+import 'package:oref/collections.dart';
2.1.1 #
Status: Released (2025-09-24)
π BUG FIXES #
Fix reset state to memoized store root
Previously, memoization reset depended on widget effects. If the widget itself used useMemoized , the memoized node would not be reset to the top.
This has now been fixed, and widget effects no longer rely on signals to reset memoization.
2.1.0 #
Status: Released (2025-09-23)
π₯ BREAKING CHANGES #
Remove GlobalSignals.*
APIs
GlobalSignals.create(value)
->signal(null, value)
GlobalSignals.computed(getter)
->computed(null, getter)
GlobalSignals.effect(callback)
->effect(null, callback)
GlobalSignals.effectScope(callback)
->effectScope(null, callback)
Remove Widget Reference
The widget reference system was overly complex and unnecessary since widgets already handle their own context and props naturally.
Direct access to widget properties is now used instead of the ref abstraction.
class MyWidget extends StatelessWidget {
MyWidget({super.key, required this.name})
final String name;
@override
Widget build(BuildContext context) {
- final ref = useRef(context);
effect(context, () {
- print(ref.widget.name);
+ print(name)
});
//...
}
}
class MyWidget2 extends StatefulWidget {
final String name;
createState() => MyState2(this);
}
class MyState2 extends State<MyWidget2> {
@override
Widget build(BuildContext context) {
- final ref = useRef();
effect(context, () {
- print(ref.widget.name);
+ print(name)
});
//...
}
}
Remove SignalBuildContext
extension #
Defining external functions by extensions was always less than ideal, and now watch
has been moved to the top level.
-final value = context.watch(count);
+final value = watch(context,count);
π§ IMPROVEMENTS #
- Improved performance: Optimized ref creation and update logic, reducing unnecessary rebuilds
2.0.2 #
Status: Released (2025-09-23)
β¨ NEW FEATURES #
Reactive Primitives
Now, signal
/computed
/effect
/effectScope
make reactive primitives
// After
-final count = GlobalSignals.create(0);
// Now
+final count = signal(null, 0);
π§ IMPROVEMENTS #
- Deprecate GlobalSignals in favor of direct imports
- Fixed widgets being unmounted still triggering effects.
2.0.1 #
- Fix
ReactiveList.add
implementation for non-nullable elements
2.0.0 #
π₯ BREAKING CHANGES #
This is a complete rewrite of Oref with breaking changes to most APIs. The new version provides better performance, cleaner APIs, and improved developer experience.
API Changes
useSignal
βsignal
: ReplaceuseSignal(context, value)
withsignal(context, value)
useComputed
βcomputed
: ReplaceuseComputed(context, computation)
withcomputed(context, computation)
useEffect
βeffect
: ReplaceuseEffect(context, callback)
witheffect(context, callback)
useEffectScope
βeffectScope
: ReplaceuseEffectScope(context)
witheffectScope(context)
- Widget Effect Hooks:
getWidgetEffect
andgetWidgetScope
renamed touseWidgetEffect
anduseWidgetScope
- Memoization:
resetMemoized
renamed toresetMemoizedFor
for clarity - Reactive Access: Direct signal calls now supported in widgets (e.g.,
Text('${count()}')
), replacing the need forSignalBuilder
in many cases
Removed Features
- Removed entire old signal system implementation (848 lines deleted)
- Removed global async computed APIs (
createGlobalAsyncComputed
,useAsyncComputed
) - Removed legacy primitive operators
- Removed old async utilities and global signal management
β¨ NEW FEATURES #
Reactive Collections
ReactiveList<T>
: Reactive wrapper for List operations with automatic dependency trackingReactiveMap<K, V>
: Reactive wrapper for Map operations with automatic dependency trackingReactiveSet<T>
: Reactive wrapper for Set operations with automatic dependency tracking- Factory Constructors: Support for widget-scoped reactive collections via
.scoped()
constructors - Global Collections: Support for global reactive collections via default constructors
Enhanced Widget Integration
SignalBuilder
: New widget for explicit reactive UI updatesSignalBuildContext
Extension: Addscontext.watch()
method for reactive value access- Direct Signal Access: Signals can now be called directly in widget build methods
- Improved Widget Effects: Better automatic rebuild triggering when signal dependencies change
New Utilities
GlobalSignals
: Utility class for managing global signal instancesbatch()
anduntrack()
: Export utility functions from alien_signals for advanced use cases- Enhanced Ref System: Improved
Ref
,StateRef
, andWidgetRef
utilities moved to dedicated utils module
π§ IMPROVEMENTS #
Performance
- Built on alien_signals v0.5.3 for optimal performance
- Removed global mutable state in computed values
- Improved memoization with better scope handling and lifecycle management
- Simplified effect and scope management for reduced overhead
Developer Experience
- Better Documentation: Comprehensive inline documentation with examples for all APIs
- Cleaner API Surface: More intuitive function names following React hooks conventions
- Simplified Widget Integration: Signals can be used directly in widget build methods without complex setup
- Better Error Handling: Improved assertions and error messages for memoization and widget context usage
- Organized Code Structure: Reorganized exports and moved utilities to separate directories for better maintainability
Architecture
- Complete Rewrite: Built from ground up with lessons learned from v1.x
- Widget Effect System: New widget effect pattern for consistent scope management
- Improved Memoization: Better widget-scoped memoization with proper lifecycle management
- Modular Design: Clear separation between core primitives, reactive collections, utilities, and widgets
- Type Safety: Enhanced type safety throughout the API surface
π MIGRATION GUIDE #
Basic Signal Usage
// v1.x
final count = useSignal(context, 0);
// v2.0
final count = signal(context, 0);
Computed Values
// v1.x
final doubled = useComputed(context, () => count.value * 2);
// v2.0
final doubled = computed(context, () => count() * 2);
Effects
// v1.x
useEffect(context, () {
print('Count: ${count.value}');
});
// v2.0
effect(context, () {
print('Count: ${count()}');
});
Widget Reactivity
// v1.x - Required SignalBuilder or manual tracking
SignalBuilder(
signal: count,
builder: (context, value, _) => Text('Count: $value'),
)
// v2.0 - Direct access supported
Text('Count: ${count()}')
// or explicit watching
Text('Count: ${context.watch(() => count())}')
// or SignalBuilder
SignalBUilder(
getter: count,
builder: (context, value) => Text('Count: $value'),
);
Reactive Collections
// v2.0 - New feature
final items = ReactiveList<String>(['a', 'b', 'c']);
final itemsScoped = ReactiveList.scoped(context, ['a', 'b', 'c']);
ποΈ PACKAGE STRUCTURE #
The new version features a well-organized package structure:
- Core:
signal
,computed
,effect
,effectScope
,useMemoized
, widget effects - Reactive:
Reactive
mixin,ReactiveList
,ReactiveMap
,ReactiveSet
- Utils:
batch
,untrack
,GlobalSignals
,Ref
utilities,SignalBuildContext
- Widgets:
SignalBuilder
for explicit reactive UI
β‘ PERFORMANCE #
- Upgraded to alien_signals v0.5.3 for optimal performance
- Removed global state management overhead
- Streamlined memoization and effect tracking
- More efficient widget rebuild patterns
π¦ DEPENDENCIES #
- alien_signals: ^0.5.3 (upgraded from ^0.4.2)
- Flutter SDK: ^3.8.1 (maintained)
1.1.3 #
- pref: Refactor binding system to use LinkedBindingNode hierarchy
1.1.2 #
- Not returning use* hooks as expected
1.1.1 #
- fix: Nested hooks cause context binding to be reset
1.1.0 #
- refactor: refactor core code to make it easier to maintain and less redundant
- refactor: Remove
createGlobalAsyncComputed
anduseAsyncComputed
- feat:
createGlobalSignal
supports automatic trigger of Widget - feat:
createGlobalComputed
supports automatic trigger of Widget - feat: Added
createGlobalAsyncResult
anduseAsyncResult
to replacecreateGlobalAsyncComputed
/useAsyncComputed
1.0.0 #
Added #
- Initial release of Oref - A reactive state management library for Flutter
- Core reactive primitives:
useSignal
- Create reactive signals with automatic dependency trackinguseComputed
- Create computed values that update when dependencies changeuseEffect
- Create side effects that run when dependencies changeuseEffectScope
- Create effect scopes for managing multiple effectsref
- Convert non-reactive Widget parameters to reactive signals
- Global APIs for use outside of widgets:
createGlobalSignal
- Create global signalscreateGlobalComputed
- Create global computed valuescreateGlobalEffect
- Create global effectscreateGlobalEffectScope
- Create global effect scopescreateGlobalAsyncComputed
- Create global async computed values
- Async computed values with
useAsyncComputed
- Batching utilities with
batch
function untrack
utility for reading signals without creating dependencies- Built-in type signal operators for enhanced type safety
- Automatic Widget rebuilding integration
- Performance optimizations with alien_signals backend
Features #
- π High performance reactive system built on alien_signals
- πͺ Magic in widgets - add reactivity to any existing Widget seamlessly
- π Automatic dependency tracking and updates
- π― Full type safety with Dart's strong type system
- π§ Flexible integration with any Flutter widget
- π¦ Lightweight with minimal overhead
Dependencies #
- Flutter SDK ^3.8.1
- alien_signals ^0.4.2