Skip to content

Commit

Permalink
Normalized events of for computed and observable boxes
Browse files Browse the repository at this point in the history
  • Loading branch information
mweststrate committed Jan 6, 2017
1 parent ab0b591 commit bf487a8
Show file tree
Hide file tree
Showing 12 changed files with 67 additions and 51 deletions.
8 changes: 4 additions & 4 deletions src/api/observe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ import {ObservableMap, IMapChange} from "../types/observablemap";
import {IObjectChange} from "../types/observableobject";
import {IComputedValue} from "../core/computedvalue";

import {IObservableValue} from "../types/observablevalue";
import {IObservableValue, IValueDidChange} from "../types/observablevalue";
import {Lambda} from "../utils/utils";
import {getAdministration} from "../types/type-utils";

export function observe<T>(value: IObservableValue<T> | IComputedValue<T>, listener: (newValue: T, oldValue: T | undefined) => void, fireImmediately?: boolean): Lambda;
export function observe<T>(value: IObservableValue<T> | IComputedValue<T>, listener: (change: IValueDidChange<T>) => void, fireImmediately?: boolean): Lambda;
export function observe<T>(observableArray: IObservableArray<T>, listener: (change: IArrayChange<T> | IArraySplice<T>) => void, fireImmediately?: boolean): Lambda;
export function observe<T>(observableMap: ObservableMap<T>, listener: (change: IMapChange<T>) => void, fireImmediately?: boolean): Lambda;
export function observe<T>(observableMap: ObservableMap<T>, property: string, listener: (newValue: T, oldValue: T | undefined) => void, fireImmediately?: boolean): Lambda;
export function observe<T>(observableMap: ObservableMap<T>, property: string, listener: (change: IValueDidChange<T>) => void, fireImmediately?: boolean): Lambda;
export function observe(object: Object, listener: (change: IObjectChange) => void, fireImmediately?: boolean): Lambda;
export function observe(object: Object, property: string, listener: (newValue: any, oldValue: any | undefined) => void, fireImmediately?: boolean): Lambda;
export function observe(object: Object, property: string, listener: (change: IValueDidChange<any>) => void, fireImmediately?: boolean): Lambda;
export function observe(thing, propOrCb?, cbOrFire?, fireImmediately?): Lambda {
if (typeof cbOrFire === "function")
return observeObservableProperty(thing, propOrCb, cbOrFire, fireImmediately);
Expand Down
12 changes: 9 additions & 3 deletions src/core/computedvalue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import {allowStateChangesStart, allowStateChangesEnd, createAction} from "./acti
import {createInstanceofPredicate, getNextId, valueDidChange, invariant, Lambda, unique, joinStrings} from "../utils/utils";
import {isSpyEnabled, spyReport} from "../core/spy";
import {autorun} from "../api/autorun";
import {IValueDidChange} from "../types/observablevalue";

export interface IComputedValue<T> {
get(): T;
set(value: T): void;
observe(listener: (newValue: T, oldValue: T) => void, fireImmediately?: boolean): Lambda;
observe(listener: (change: IValueDidChange<T>) => void, fireImmediately?: boolean): Lambda;
}

/**
Expand Down Expand Up @@ -157,14 +158,19 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
return valueDidChange(this.compareStructural, newValue, oldValue);
}

observe(listener: (newValue: T, oldValue: T | undefined) => void, fireImmediately?: boolean): Lambda {
observe(listener: (change: IValueDidChange<T>) => void, fireImmediately?: boolean): Lambda {
let firstTime = true;
let prevValue: T | undefined = undefined;
return autorun(() => {
let newValue = this.get();
if (!firstTime || fireImmediately) {
const prevU = untrackedStart();
listener(newValue, prevValue);
listener({
type: "update",
object: this,
newValue,
oldValue: prevValue
});
untrackedEnd(prevU);
}
firstTime = false;
Expand Down
2 changes: 1 addition & 1 deletion src/mobx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export { IInterceptable, IInterceptor } from "./types/in
export { IListenable } from "./types/listen-utils";
export { IObjectWillChange, IObjectChange, IObservableObject, isObservableObject } from "./types/observableobject";

export { /* 3.0: IValueDidChange, */ IValueWillChange, IObservableValue } from "./types/observablevalue";
export { IValueDidChange, IValueWillChange, IObservableValue } from "./types/observablevalue";
export { IObservableArray, IArrayWillChange, IArrayWillSplice, IArrayChange, IArraySplice, isObservableArray } from "./types/observablearray";
export { IKeyValueMap, ObservableMap, IMapEntries, IMapEntry, IMapWillChange, IMapChange, isObservableMap, map, IObservableMapInitialValues, IMap } from "./types/observablemap"

Expand Down
9 changes: 2 additions & 7 deletions src/types/listen-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,14 @@ export function registerListener<T>(listenable: IListenable, handler: Function):
});
}

export function notifyListeners<T>(listenable: IListenable, change: T | T[]) {
export function notifyListeners<T>(listenable: IListenable, change: T) {
const prevU = untrackedStart();
let listeners = listenable.changeListeners;
if (!listeners)
return;
listeners = listeners.slice();
for (let i = 0, l = listeners.length; i < l; i++) {
if (Array.isArray(change)) {
listeners[i].apply(null, change);
}
else {
listeners[i](change);
}
listeners[i](change);
}
untrackedEnd(prevU);
}
25 changes: 20 additions & 5 deletions src/types/observablevalue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export interface IValueWillChange<T> {
newValue: T;
}

export interface IValueDidChange<T> extends IValueWillChange<T> {
oldValue: T | undefined;
}

export type IUNCHANGED = {};

export const UNCHANGED: IUNCHANGED = {};
Expand All @@ -20,7 +24,7 @@ export interface IObservableValue<T> {
get(): T;
set(value: T): void;
intercept(handler: IInterceptor<IValueWillChange<T>>): Lambda;
observe(listener: (newValue: T, oldValue: T) => void, fireImmediately?: boolean): Lambda;
observe(listener: (change: IValueDidChange<T>) => void, fireImmediately?: boolean): Lambda;
}

export class ObservableValue<T> extends BaseAtom implements IObservableValue<T>, IInterceptable<IValueWillChange<T>>, IListenable {
Expand Down Expand Up @@ -76,8 +80,14 @@ export class ObservableValue<T> extends BaseAtom implements IObservableValue<T>,
const oldValue = this.value;
this.value = newValue;
this.reportChanged();
if (hasListeners(this))
notifyListeners(this, [newValue, oldValue]); // in 3.0, use an object instead!
if (hasListeners(this)) {
notifyListeners(this, {
type: "update",
object: this,
newValue,
oldValue
});
}
}

public get(): T {
Expand All @@ -89,9 +99,14 @@ export class ObservableValue<T> extends BaseAtom implements IObservableValue<T>,
return registerInterceptor(this, handler);
}

public observe(listener: (newValue: T, oldValue: T | undefined) => void, fireImmediately?: boolean): Lambda {
public observe(listener: (change: IValueDidChange<T>) => void, fireImmediately?: boolean): Lambda {
if (fireImmediately)
listener(this.value, undefined);
listener({
object: this,
type: "update",
newValue: this.value,
oldValue: undefined
});
return registerListener(this, listener);
}

Expand Down
4 changes: 2 additions & 2 deletions test/babel/babel-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ test('decorators', function(t) {

var events = [];
var d1 = observe(o, (ev) => events.push(ev.name, ev.oldValue));
var d2 = observe(o, 'price', (newValue, oldValue) => events.push(newValue, oldValue));
var d3 = observe(o, 'total', (newValue, oldValue) => events.push(newValue, oldValue));
var d2 = observe(o, 'price', (ev) => events.push(ev.newValue, ev.oldValue));
var d3 = observe(o, 'total', (ev) => events.push(ev.newValue, ev.oldValue));

o.price = 4;

Expand Down
8 changes: 4 additions & 4 deletions test/makereactive.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ var voidObserver = function(){};

function buffer() {
var b = [];
var res = function(newValue) {
b.push(newValue);
var res = function(x) {
b.push(x);
};
res.toArray = function() {
return b;
Expand Down Expand Up @@ -161,7 +161,7 @@ test('observable4', function(t) {
var b = buffer();
m.observe(m.computed(function() {
return x.map(function(d) { return d.x });
}), b, true);
}), x => b(x.newValue), true);

x[0].x = 3;
x.shift();
Expand All @@ -177,7 +177,7 @@ test('observable4', function(t) {
var b2 = buffer();
m.observe(m.computed(function() {
return x2.map(function(d) { return d.x });
}), b2, true);
}), x => b2(x.newValue), true);

x2[0].x = 3;
x2.shift();
Expand Down
10 changes: 5 additions & 5 deletions test/observables.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ var voidObserver = function(){};

function buffer() {
var b = [];
var res = function(newValue) {
b.push(newValue);
var res = function(x) {
b.push(x.newValue);
};
res.toArray = function() {
return b;
Expand Down Expand Up @@ -746,7 +746,7 @@ test('nested observable2', function(t) {
});

var b = [];
var sub = m.observe(total, function(x) { b.push(x); }, true);
var sub = m.observe(total, function(x) { b.push(x.newValue); }, true);

price.set(150);
factor.set(7); // triggers innerCalc twice, because changing the outcome triggers the outer calculation which recreates the inner calculation
Expand Down Expand Up @@ -777,7 +777,7 @@ test('expr', function(t) {
});

var b = [];
var sub = m.observe(total, function(x) { b.push(x); }, true);
var sub = m.observe(total, function(x) { b.push(x.newValue); }, true);

price.set(150);
factor.set(7); // triggers innerCalc twice, because changing the outcome triggers the outer calculation which recreates the inner calculation
Expand Down Expand Up @@ -870,7 +870,7 @@ test('expr2', function(t) {
});

var b = [];
var sub = m.observe(total, function(x) { b.push(x); }, true);
var sub = m.observe(total, function(x) { b.push(x.newValue); }, true);

price.set(150);
factor.set(7); // triggers innerCalc twice, because changing the outcome triggers the outer calculation which recreates the inner calculation
Expand Down
28 changes: 14 additions & 14 deletions test/observe.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,44 @@ var m = require('..');
test('observe object and map properties', function(t) {
var map = m.map({ a : 1 });
var events = [];

t.throws(function() {
m.observe(map, "b", function() {});
});
var d1 = m.observe(map, "a", function(newV, oldV) {
events.push([newV, oldV]);

var d1 = m.observe(map, "a", function(e) {
events.push([e.newValue, e.oldValue]);
});

map.set("a", 2);
map.set("a", 3);
d1();
map.set("a", 4);

var o = m.observable({
a: 5
});

t.throws(function() {
m.observe(o, "b", function() {});
});
var d2 = m.observe(o, "a", function(newV, oldV) {
events.push([newV, oldV]);
var d2 = m.observe(o, "a", function(e) {
events.push([e.newValue, e.oldValue]);
});

o.a = 6;
o.a = 7;
d2();
o.a = 8;

t.deepEqual(events, [
[2, 1],
[3, 2],
[6, 5],
[7, 6]
]);
t.end();

t.end();
});

test('observe computed values', function(t) {
Expand All @@ -51,10 +51,10 @@ test('observe computed values', function(t) {
var f = m.observable(0);
var c = m.computed(function() { return v.get(); });

var d2 = c.observe(function(newV, oldV) {
var d2 = c.observe(function(e) {
v.get();
f.get();
events.push([newV, oldV]);
events.push([e.newValue, e.oldValue]);
});

v.set(6);
Expand Down
4 changes: 2 additions & 2 deletions test/perf/perf.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ test('lots of unused computables', function(t) {
});

var sum = 0;
var subscription = mobx.observe(b, function(newValue) {
sum = newValue;
var subscription = mobx.observe(b, function(e) {
sum = e.newValue;
}, true);

t.equal(sum, 49995000);
Expand Down
4 changes: 2 additions & 2 deletions test/tojs.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ test('json2', function(t) {
var ab = [];
var tb = [];

m.observe(analyze, function(d) { ab.push(d); }, true);
m.observe(alltags, function(d) { tb.push(d); }, true);
m.observe(analyze, function(d) { ab.push(d.newValue); }, true);
m.observe(alltags, function(d) { tb.push(d.newValue); }, true);

o.todos[0].details.url = "boe";
o.todos[1].details.url = "ba";
Expand Down
4 changes: 2 additions & 2 deletions test/typescript/typescript-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ test('decorators', function(t) {

var events: any[] = [];
var d1 = observe(o, (ev: IObjectChange) => events.push(ev.name, ev.oldValue));
var d2 = observe(o, 'price', (newValue, oldValue) => events.push(newValue, oldValue));
var d3 = observe(o, 'total', (newValue, oldValue) => events.push(newValue, oldValue));
var d2 = observe(o, 'price', (ev) => events.push(ev.newValue, ev.oldValue));
var d3 = observe(o, 'total', (ev) => events.push(ev.newValue, ev.oldValue));

o.price = 4;

Expand Down

0 comments on commit bf487a8

Please sign in to comment.