Skip to content

Commit

Permalink
fix: Fixed a bug that caused unrelated items to be updated when refs …
Browse files Browse the repository at this point in the history
…were updated internally.
  • Loading branch information
mathrunet committed Jul 15, 2023
1 parent 27cdc98 commit b3d1039
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 33 deletions.
2 changes: 2 additions & 0 deletions packages/katana_scoped/lib/src/ref.dart
Expand Up @@ -89,6 +89,8 @@ abstract class Ref {
/// {@endtemplate}
TResult getScopedValue<TResult, TScopedValue extends ScopedValue<TResult>>(
TScopedValue Function(Ref ref) provider, {
void Function(ScopedValueState<TResult, TScopedValue> state)?
onInitOrUpdate,
bool listen = false,
String? name,
});
Expand Down
3 changes: 3 additions & 0 deletions packages/katana_scoped/lib/src/scoped_ref.dart
Expand Up @@ -59,13 +59,16 @@ class AppRef implements Ref {
@override
TResult getScopedValue<TResult, TScopedValue extends ScopedValue<TResult>>(
TScopedValue Function(Ref ref) provider, {
void Function(ScopedValueState<TResult, TScopedValue> state)?
onInitOrUpdate,
bool listen = false,
String? name,
}) {
return _scopedValueContainer
.getScopedValueState<TResult, TScopedValue>(
() => provider(this),
name: name,
onInitOrUpdate: onInitOrUpdate,
scope: ScopedLoggerScope.app,
managedBy: toString(),
loggerAdapters: loggerAdapters,
Expand Down
33 changes: 22 additions & 11 deletions packages/katana_scoped/lib/src/scoped_value.dart
Expand Up @@ -57,13 +57,12 @@ abstract class ScopedValueState<TResult,
TScopedValue extends ScopedValue<TResult>> {
bool _disposed = false;
late TScopedValue? _value;
final Set<ScopedValueState> _ancestorStates = {};
final Set<ScopedValueListener> _listeners = {};
final Set<VoidCallback> _callbacks = {};
_ScopedValueRef? _ref;
late final DynamicMap _baseParameters;
late final List<LoggerAdapter> _loggerAdapters;
// ignore: prefer_final_fields
bool _referencedByChildState = false;

/// Returns `true` if [ScopedValue] should be automatically discarded when it is no longer referenced by any widget.
///
Expand All @@ -83,15 +82,8 @@ abstract class ScopedValueState<TResult,
return ref!;
}

/// `True` if the state is further monitored by [Ref] passed to [ScopedValue].
///
/// When [setState] of the descendant [ScopedValue] is executed and the update of the state is notified, [didUpdateValue] is called, so check this value and change the state accordingly.
///
/// [ScopedValue]に渡された[Ref]によってさらに状態を監視されている場合に`true`になります。
///
/// 子孫の[ScopedValue][setState]が実行されて状態の更新が通知された場合、[didUpdateValue]が呼ばれるのでこの値を確認して適宜状態を変更してください。
bool get referencedByChildState {
return _ref?.referencedByChildState ?? false;
void _addParent(ScopedValueState state) {
_ancestorStates.add(state);
}

void _addListener(ScopedValueListener listener, [VoidCallback? callback]) {
Expand All @@ -116,6 +108,16 @@ abstract class ScopedValueState<TResult,
for (final callback in _callbacks) {
callback.call();
}
for (final ancestor in _ancestorStates) {
ancestor._notifyAncestor();
}
}

void _notifyAncestor() {
didUpdateDescendant();
for (final ancestor in _ancestorStates) {
ancestor._notifyAncestor();
}
}

void _setValue(TScopedValue value) {
Expand Down Expand Up @@ -206,6 +208,12 @@ abstract class ScopedValueState<TResult,
@mustCallSuper
void didUpdateValue(covariant TScopedValue oldValue) {}

/// The original [ScopedValue] is notified when a [ScopedValue] executed through the internal [Ref] is updated.
///
/// 内部の[Ref]を通して実行された[ScopedValue]が更新された際にその元となった[ScopedValue]に通知されます。
@mustCallSuper
void didUpdateDescendant() {}

/// Executed when a value is created.
///
/// 値が作成された際に実行されます。
Expand All @@ -229,8 +237,11 @@ abstract class ScopedValueState<TResult,
@mustCallSuper
void dispose() {
assert(!disposed, "Value is already disposed.");
_ref = null;
_disposed = true;
_callbacks.clear();
_listeners.clear();
_ancestorStates.clear();
_sendLog(ScopedLoggerEvent.dispose);
}

Expand Down
3 changes: 3 additions & 0 deletions packages/katana_scoped/lib/src/scoped_value_listener.dart
Expand Up @@ -125,6 +125,8 @@ class ScopedValueListener {
TResult
getScopedValueResult<TResult, TScopedValue extends ScopedValue<TResult>>(
TScopedValue Function() provider, {
void Function(ScopedValueState<TResult, TScopedValue> state)?
onInitOrUpdate,
bool listen = false,
String? name,
}) {
Expand All @@ -141,6 +143,7 @@ class ScopedValueListener {
state._sendLog(ScopedLoggerEvent.listen, additionalParameter: {
ScopedLoggerEvent.listenedKey: __listendBy,
});
onInitOrUpdate?.call(state);
},
name: name,
scope: _scope,
Expand Down
20 changes: 12 additions & 8 deletions packages/katana_scoped/lib/src/scoped_value_ref.dart
Expand Up @@ -135,11 +135,14 @@ class ScopedValueRef implements Ref {
@override
TResult getScopedValue<TResult, TScopedValue extends ScopedValue<TResult>>(
TScopedValue Function(Ref ref) provider, {
void Function(ScopedValueState<TResult, TScopedValue> state)?
onInitOrUpdate,
bool listen = false,
String? name,
}) {
return _listener.getScopedValueResult<TResult, TScopedValue>(
() => provider(this),
onInitOrUpdate: onInitOrUpdate,
listen: listen,
name: name,
);
Expand Down Expand Up @@ -177,19 +180,23 @@ class _ScopedValueRef implements Ref {
final Ref ref;
final ScopedValueState state;

bool get referencedByChildState => state._referencedByChildState;

@override
TResult getScopedValue<TResult, TScopedValue extends ScopedValue<TResult>>(
TScopedValue Function(Ref ref) provider, {
void Function(ScopedValueState<TResult, TScopedValue> state)?
onInitOrUpdate,
bool listen = false,
String? name,
}) {
if (listen) {
state._referencedByChildState = true;
}
return ref.getScopedValue(
provider,
onInitOrUpdate: (ScopedValueState<TResult, TScopedValue> state) {
if (state.disposed) {
return;
}
state._addParent(this.state);
onInitOrUpdate?.call(state);
},
listen: listen,
name: name,
);
Expand All @@ -201,9 +208,6 @@ class _ScopedValueRef implements Ref {
String? name,
bool listen = false,
}) {
if (listen) {
state._referencedByChildState = true;
}
return ref.getAlreadyExistsScopedValue(
listen: listen,
name: name,
Expand Down
8 changes: 7 additions & 1 deletion packages/katana_scoped/lib/value/cache.dart
Expand Up @@ -106,11 +106,17 @@ class _CacheValueState<T> extends ScopedValueState<T, _CacheValue<T>> {
@override
void didUpdateValue(_CacheValue<T> oldValue) {
super.didUpdateValue(oldValue);
if (!equalsKeys(value.keys, oldValue.keys) || referencedByChildState) {
if (!equalsKeys(value.keys, oldValue.keys)) {
_value = value.callback(ref);
}
}

@override
void didUpdateDescendant() {
super.didUpdateDescendant();
_value = value.callback(ref);
}

@override
T build() => _value;
}
22 changes: 10 additions & 12 deletions packages/katana_scoped/lib/value/query.dart
Expand Up @@ -121,18 +121,16 @@ class _QueryValueState<T> extends ScopedValueState<T, _QueryValue<T>> {
}

@override
void didUpdateValue(_QueryValue<T> oldValue) {
super.didUpdateValue(oldValue);
if (referencedByChildState) {
final oldVal = _value;
if (oldVal is Listenable) {
oldVal.removeListener(_handledOnUpdate);
}
_value = _callback();
final newVal = _value;
if (newVal is Listenable) {
newVal.addListener(_handledOnUpdate);
}
void didUpdateDescendant() {
super.didUpdateDescendant();
final oldVal = _value;
if (oldVal is Listenable) {
oldVal.removeListener(_handledOnUpdate);
}
_value = _callback();
final newVal = _value;
if (newVal is Listenable) {
newVal.addListener(_handledOnUpdate);
}
}

Expand Down
16 changes: 15 additions & 1 deletion packages/katana_scoped/lib/value/watch.dart
Expand Up @@ -136,7 +136,7 @@ class _WatchValueState<T> extends ScopedValueState<T, _WatchValue<T>> {
@override
void didUpdateValue(_WatchValue<T> oldValue) {
super.didUpdateValue(oldValue);
if (!equalsKeys(value.keys, oldValue.keys) || referencedByChildState) {
if (!equalsKeys(value.keys, oldValue.keys)) {
final oldVal = _value;
if (oldVal is Listenable) {
oldVal.removeListener(_handledOnUpdate);
Expand All @@ -149,6 +149,20 @@ class _WatchValueState<T> extends ScopedValueState<T, _WatchValue<T>> {
}
}

@override
void didUpdateDescendant() {
super.didUpdateDescendant();
final oldVal = _value;
if (oldVal is Listenable) {
oldVal.removeListener(_handledOnUpdate);
}
_value = value.callback(ref);
final newVal = _value;
if (newVal is Listenable) {
newVal.addListener(_handledOnUpdate);
}
}

@override
void dispose() {
super.dispose();
Expand Down

0 comments on commit b3d1039

Please sign in to comment.