oref 2.4.2 copy "oref: ^2.4.2" to clipboard
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 #

Status: Released (2025-09-27)

πŸ› BUG FIXES #

  • fix(async): Field 'node' has not been initialized.

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.

Thx @definev2 (Zen Bui) - 1970659750242328584

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: Replace useSignal(context, value) with signal(context, value)
  • useComputed β†’ computed: Replace useComputed(context, computation) with computed(context, computation)
  • useEffect β†’ effect: Replace useEffect(context, callback) with effect(context, callback)
  • useEffectScope β†’ effectScope: Replace useEffectScope(context) with effectScope(context)
  • Widget Effect Hooks: getWidgetEffect and getWidgetScope renamed to useWidgetEffect and useWidgetScope
  • Memoization: resetMemoized renamed to resetMemoizedFor for clarity
  • Reactive Access: Direct signal calls now supported in widgets (e.g., Text('${count()}')), replacing the need for SignalBuilder 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 tracking
  • ReactiveMap<K, V>: Reactive wrapper for Map operations with automatic dependency tracking
  • ReactiveSet<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 updates
  • SignalBuildContext Extension: Adds context.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 instances
  • batch() and untrack(): Export utility functions from alien_signals for advanced use cases
  • Enhanced Ref System: Improved Ref, StateRef, and WidgetRef 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 and useAsyncComputed
  • feat: createGlobalSignal supports automatic trigger of Widget
  • feat: createGlobalComputed supports automatic trigger of Widget
  • feat: Added createGlobalAsyncResult and useAsyncResult to replace createGlobalAsyncComputed/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 tracking
    • useComputed - Create computed values that update when dependencies change
    • useEffect - Create side effects that run when dependencies change
    • useEffectScope - Create effect scopes for managing multiple effects
    • ref - Convert non-reactive Widget parameters to reactive signals
  • Global APIs for use outside of widgets:
    • createGlobalSignal - Create global signals
    • createGlobalComputed - Create global computed values
    • createGlobalEffect - Create global effects
    • createGlobalEffectScope - Create global effect scopes
    • createGlobalAsyncComputed - 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
8
likes
160
points
677
downloads

Publisher

verified publishermedz.dev

Weekly Downloads

A reactive state management library for Flutter that adds magic to any Widget with signals, computed values, and effects powered by alien_signals.

Repository (GitHub)
View/report issues

Topics

#signals #reactive #state-management #alien-signals

Documentation

API reference

Funding

Consider supporting this project:

github.com
opencollective.com

License

MIT (license)

Dependencies

alien_signals, flutter

More

Packages that depend on oref