Skip to content

Commit

Permalink
feat: Add onDispose callback to Computed, such that old values ca…
Browse files Browse the repository at this point in the history
…n be properly disposed mobxjs#857
  • Loading branch information
fzyzcjy committed Sep 4, 2022
1 parent e1df03a commit bbd9020
Showing 1 changed file with 37 additions and 14 deletions.
51 changes: 37 additions & 14 deletions mobx/lib/src/core/computed.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,27 @@ class Computed<T> extends Atom implements Derivation, ObservableValue<T> {
/// A computed value is _cached_ and it recomputes only when the dependent observables actually
/// change. This makes them fast and you are free to use them throughout your application. Internally
/// MobX uses a 2-phase change propagation that ensures no unnecessary computations are performed.
factory Computed(T Function() fn,
{String? name,
ReactiveContext? context,
EqualityComparer<T>? equals}) =>
Computed._(context ?? mainContext, fn, name: name, equals: equals);

Computed._(ReactiveContext context, this._fn, {String? name, this.equals})
factory Computed(
T Function() fn, {
String? name,
ReactiveContext? context,
EqualityComparer<T>? equals,
void Function(T)? disposeValue,
}) =>
Computed._(
context ?? mainContext,
fn,
(v) => v == null ? null : disposeValue?.call(v),
name: name,
equals: equals,
);

Computed._(ReactiveContext context, this._fn, this._disposeValue,
{String? name, this.equals})
: super._(context, name: name ?? context.nameFor('Computed'));

final EqualityComparer<T>? equals;
final void Function(T?) _disposeValue;

@override
MobXCaughtException? _errorValue;
Expand All @@ -61,10 +72,19 @@ class Computed<T> extends Atom implements Derivation, ObservableValue<T> {
// ignore: prefer_final_fields
DerivationState _dependenciesState = DerivationState.notTracking;

T? _value;

bool _isComputing = false;

T? get _cachedValue => __cachedValue;

// do NOT directly set `__cachedValue`. Instead, set `_cachedValue`,
// which will properly dispose the old value.
T? __cachedValue;

set _cachedValue(T? newValue) {
_disposeValue(__cachedValue);
__cachedValue = newValue;
}

@override
T get value {
if (_isComputing) {
Expand All @@ -75,7 +95,7 @@ class Computed<T> extends Atom implements Derivation, ObservableValue<T> {
if (!_context.isWithinBatch && _observers.isEmpty) {
if (_context._shouldCompute(this)) {
_context.startBatch();
_value = computeValue(track: false);
_cachedValue = computeValue(track: false);
_context.endBatch();
}
} else {
Expand All @@ -91,7 +111,7 @@ class Computed<T> extends Atom implements Derivation, ObservableValue<T> {
throw _errorValue!;
}

return _value as T;
return _cachedValue as T;
}

T? computeValue({required bool track}) {
Expand Down Expand Up @@ -123,7 +143,7 @@ class Computed<T> extends Atom implements Derivation, ObservableValue<T> {
@override
void _suspend() {
_context._clearObservables(this);
_value = null;
_cachedValue = null;
}

@override
Expand All @@ -136,7 +156,7 @@ class Computed<T> extends Atom implements Derivation, ObservableValue<T> {
_context.spyReport(ComputedValueSpyEvent(this, name: name));
}

final oldValue = _value;
final oldValue = _cachedValue;
final wasSuspended = _dependenciesState == DerivationState.notTracking;
final hadCaughtException = _context._hasCaughtException(this);

Expand All @@ -148,7 +168,10 @@ class Computed<T> extends Atom implements Derivation, ObservableValue<T> {
wasSuspended || changedException || !_isEqual(oldValue, newValue);

if (changed) {
_value = newValue;
_cachedValue = newValue;
} else {
// the new value is not used, so we should dispose it
_disposeValue(newValue);
}

return changed;
Expand Down

0 comments on commit bbd9020

Please sign in to comment.