From 72f87ed37e39e0bc0adfe570b0549e95f5bb43ed Mon Sep 17 00:00:00 2001 From: jinyus Date: Mon, 1 Jan 2024 11:15:14 -0500 Subject: [PATCH 1/4] Add addAll() method to Listeners class --- state_beacon/lib/src/listeners.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/state_beacon/lib/src/listeners.dart b/state_beacon/lib/src/listeners.dart index b64d3f3e..1f74e1fd 100644 --- a/state_beacon/lib/src/listeners.dart +++ b/state_beacon/lib/src/listeners.dart @@ -16,6 +16,11 @@ class Listeners { return added; } + void addAll(Iterable items) { + _set.addAll(items); + _list.addAll(items); + } + bool remove(EffectClosure item) { bool removed = _set.remove(item); if (removed) { From 7e278c7f14fb5502c91b8ba5c0cf1c4c1f2bbb05 Mon Sep 17 00:00:00 2001 From: jinyus Date: Mon, 1 Jan 2024 11:16:17 -0500 Subject: [PATCH 2/4] only hide value access from current effects when usimg untracked instead hiding it from all listeners --- state_beacon/lib/src/base_beacon.dart | 15 +++++++++++++-- state_beacon/lib/src/untracked.dart | 22 ++++++++++++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/state_beacon/lib/src/base_beacon.dart b/state_beacon/lib/src/base_beacon.dart index 4d0ca28b..5c3fba58 100644 --- a/state_beacon/lib/src/base_beacon.dart +++ b/state_beacon/lib/src/base_beacon.dart @@ -63,7 +63,9 @@ abstract class BaseBeacon implements ValueListenable { if (_isEmpty) { throw UninitializeLazyReadException(); } + if (isRunningUntracked()) { + // if we are running untracked, we don't want to add the current effect to the listeners return _value; } @@ -76,8 +78,17 @@ abstract class BaseBeacon implements ValueListenable { void _notifyOrDeferBatch() { if (isRunningUntracked()) { - return; - } else if (_isRunningBatchJob()) { + final currentEffects = []; + for (final effect in _effectStack) { + _listeners.remove(effect.func); + currentEffects.add(effect.func); + } + reAddListeners = () { + _listeners.addAll(currentEffects); + }; + } + + if (_isRunningBatchJob()) { _listenersToPingAfterBatchJob.addAll(_listeners.items); } else { _notifyListeners(); diff --git a/state_beacon/lib/src/untracked.dart b/state_beacon/lib/src/untracked.dart index 391adfbf..ac51be4f 100644 --- a/state_beacon/lib/src/untracked.dart +++ b/state_beacon/lib/src/untracked.dart @@ -1,9 +1,27 @@ +import 'package:state_beacon/src/common.dart'; + var _untrackedStack = 0; bool isRunningUntracked() => _untrackedStack > 0; +// when running untracked, we will remove the current effects from the beacon's listeners +// so they won't be notified when the value is accessed; +// therefore, we need to re-add them after the untracked block is done +VoidCallback? reAddListeners; + void doUntracked(void Function() fn) { + if (isRunningUntracked()) { + fn(); + return; + } + _untrackedStack++; - fn(); - _untrackedStack--; + + try { + fn(); + } finally { + _untrackedStack--; + reAddListeners?.call(); + reAddListeners = null; + } } From 20139f5a33c89fb41bdf162a45d89bcde1b699ee Mon Sep 17 00:00:00 2001 From: jinyus Date: Mon, 1 Jan 2024 11:16:31 -0500 Subject: [PATCH 3/4] add more tests for untracked. --- state_beacon/test/untracked_test.dart | 28 ++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/state_beacon/test/untracked_test.dart b/state_beacon/test/untracked_test.dart index 512fe17f..56f1a705 100644 --- a/state_beacon/test/untracked_test.dart +++ b/state_beacon/test/untracked_test.dart @@ -5,20 +5,42 @@ void main() { test('should not send notification when doing untracked updates', () { final age = Beacon.writable(10); var callCount = 0; - age.subscribe((_) => callCount++); Beacon.createEffect(() { age.value; + callCount++; Beacon.untracked(() { age.value = 15; }); }); - expect(callCount, equals(0)); + expect(callCount, equals(1)); expect(age.value, 15); age.value = 20; + expect(callCount, equals(2)); + }); + + test('should not send notification when doing nested untracked updates', () { + final age = Beacon.writable(10); + var callCount = 0; + + Beacon.createEffect(() { + age.value; + callCount++; + Beacon.untracked(() { + age.value = 15; + Beacon.untracked(() { + age.value = 20; + }); + }); + }); + expect(callCount, equals(1)); + expect(age.value, 20); + + age.value = 25; + expect(callCount, equals(2)); }); test('should not send notification when doing untracked access', () { @@ -29,10 +51,10 @@ void main() { Beacon.createEffect(() { age.value; + callCount++; Beacon.untracked(() { name.value; }); - callCount++; }); expect(callCount, equals(1)); From 0ddb295df4e419a1c95c4748d160ef77a5f0d7d2 Mon Sep 17 00:00:00 2001 From: jinyus Date: Mon, 1 Jan 2024 11:27:59 -0500 Subject: [PATCH 4/4] v0.15.0 --- state_beacon/CHANGELOG.md | 4 ++++ state_beacon/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/state_beacon/CHANGELOG.md b/state_beacon/CHANGELOG.md index 800a1da3..9825a279 100644 --- a/state_beacon/CHANGELOG.md +++ b/state_beacon/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.15.0 + +- Beacon.untracked() now only hide the update/access from encompassing effects. + ## 0.14.6 - Add `tryCatch` method to AsyncValue class that executes a future and returns an AsyncData or AsyncError diff --git a/state_beacon/pubspec.yaml b/state_beacon/pubspec.yaml index 92c04bed..a51932dd 100644 --- a/state_beacon/pubspec.yaml +++ b/state_beacon/pubspec.yaml @@ -1,6 +1,6 @@ name: state_beacon description: A reactive primitive and simple state managerment solution for dart and flutter -version: 0.14.6 +version: 0.15.0 repository: https://github.com/jinyus/dart_beacon environment: