FRPtools 1.2.0
- add the ability to have comparators for complex types - computed.unsubscribeAll() to give more cleanup options
This commit is contained in:
parent
fc59945966
commit
c386545cb6
@ -46,6 +46,26 @@ it will provide the count of remaining subscriptions.
|
|||||||
```js
|
```js
|
||||||
const unsubscribe = inViewport.subscribe(console.log.bind(console));
|
const unsubscribe = inViewport.subscribe(console.log.bind(console));
|
||||||
const remainingSubscriptionCount = unsubscribe();
|
const remainingSubscriptionCount = unsubscribe();
|
||||||
|
|
||||||
|
inViewport.unsubscribeAll(); // Call unsubscribeAll to remove child observables/computeds.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Provide a comparator for complex types
|
||||||
|
|
||||||
|
When storing a type that is not determined to be equal with simple equality (===), provide a
|
||||||
|
function to determine in the new provided value should be propagated to dependents.
|
||||||
|
|
||||||
|
```js
|
||||||
|
function setEquals(a, b) {
|
||||||
|
return (
|
||||||
|
a instanceof Set &&
|
||||||
|
b instanceof Set &&
|
||||||
|
[...a].reduce((acc, d) => acc && b.has(d), true) &&
|
||||||
|
[...b].reduce((acc, d) => acc && a.has(d), true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const a = observable(new Set([1, 2]), setEquals);
|
||||||
```
|
```
|
||||||
|
|
||||||
# [computed](./src/computed.js)
|
# [computed](./src/computed.js)
|
||||||
@ -111,6 +131,33 @@ showDialog.subscribe(console.log.bind(console));
|
|||||||
inViewport(false); // showDialog result recomputed and `false` is written to the console.
|
inViewport(false); // showDialog result recomputed and `false` is written to the console.
|
||||||
shouldShow(false); // showDialog result recomputed, console.log is not called.
|
shouldShow(false); // showDialog result recomputed, console.log is not called.
|
||||||
showDialog(); // showDialog does not recompute, console.log is not called. `false` is returned.
|
showDialog(); // showDialog does not recompute, console.log is not called. `false` is returned.
|
||||||
|
|
||||||
|
showDialog.detach(); // Call detach to remove this computed from the logic tree.
|
||||||
|
showDialog.unsubscribeAll(); // Call unsubscribeAll to remove child observables/computeds.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Provide a comparator for complex types
|
||||||
|
|
||||||
|
When the computed result is a type that is not determined to be equal with simple equality (===),
|
||||||
|
provide a function to determine in the new provided value should be propagated to dependents.
|
||||||
|
|
||||||
|
```js
|
||||||
|
function setEquals(a, b) {
|
||||||
|
return (
|
||||||
|
a instanceof Set &&
|
||||||
|
b instanceof Set &&
|
||||||
|
[...a].reduce((acc, d) => acc && b.has(d), true) &&
|
||||||
|
[...b].reduce((acc, d) => acc && a.has(d), true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _intersection(a, b) {
|
||||||
|
return new Set([...a].filter(x => b.has(x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
const a = observable(new Set([1, 2]), setEquals);
|
||||||
|
const b = observable(new Set([2, 3]), setEquals);
|
||||||
|
const intersection = computed(_intersection, [a, b], setEquals);
|
||||||
```
|
```
|
||||||
|
|
||||||
# [bundle](./src/bundle.js)
|
# [bundle](./src/bundle.js)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "frptools",
|
"name": "frptools",
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"description": "Observable and Computed data streams",
|
"description": "Observable and Computed data streams",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"jsnext:main": "src/index.js",
|
"jsnext:main": "src/index.js",
|
||||||
|
|||||||
@ -155,4 +155,37 @@ describe('computed', () => {
|
|||||||
expect(b()).toEqual(4);
|
expect(b()).toEqual(4);
|
||||||
expect(c()).toEqual(7);
|
expect(c()).toEqual(7);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('uses a comparator', () => {
|
||||||
|
function setEquals(a, b) {
|
||||||
|
return (
|
||||||
|
a instanceof Set &&
|
||||||
|
b instanceof Set &&
|
||||||
|
[...a].reduce((acc, d) => acc && b.has(d), true) &&
|
||||||
|
[...b].reduce((acc, d) => acc && a.has(d), true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let runCount = 0;
|
||||||
|
|
||||||
|
function intersection(a, b) {
|
||||||
|
runCount += 1;
|
||||||
|
return new Set([...a].filter(x => b.has(x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
const a = observable(new Set([1, 2]), setEquals);
|
||||||
|
const b = observable(new Set([2, 3]), setEquals);
|
||||||
|
const ABintersection = computed(intersection, [a, b], setEquals);
|
||||||
|
|
||||||
|
expect(runCount).toEqual(0);
|
||||||
|
expect([...ABintersection()]).toEqual([2]);
|
||||||
|
expect(runCount).toEqual(1);
|
||||||
|
b(new Set([3, 2]));
|
||||||
|
expect([...ABintersection()]).toEqual([2]);
|
||||||
|
expect(runCount).toEqual(1);
|
||||||
|
b(new Set([3, 2, 1]));
|
||||||
|
expect(runCount).toEqual(1);
|
||||||
|
expect([...ABintersection()]).toEqual([1, 2]);
|
||||||
|
expect(runCount).toEqual(2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -61,4 +61,26 @@ describe('observable', () => {
|
|||||||
expect(a(4)).toEqual(4);
|
expect(a(4)).toEqual(4);
|
||||||
expect(runCount).toEqual(3);
|
expect(runCount).toEqual(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('uses a comparator', () => {
|
||||||
|
function setEquals(a, b) {
|
||||||
|
return (
|
||||||
|
a instanceof Set &&
|
||||||
|
b instanceof Set &&
|
||||||
|
[...a].reduce((acc, d) => acc && b.has(d), true) &&
|
||||||
|
[...b].reduce((acc, d) => acc && a.has(d), true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let runCount = 0;
|
||||||
|
|
||||||
|
const a = observable(new Set([1, 2]), setEquals);
|
||||||
|
a.subscribe(() => (runCount += 1));
|
||||||
|
expect([...a()]).toEqual([1, 2]);
|
||||||
|
expect(runCount).toEqual(0);
|
||||||
|
expect([...a(new Set([2, 1]))]).toEqual([1, 2]);
|
||||||
|
expect(runCount).toEqual(0);
|
||||||
|
expect([...a(new Set([3, 2, 1]))]).toEqual([3, 2, 1]);
|
||||||
|
expect(runCount).toEqual(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { eq } from './util.js';
|
||||||
|
|
||||||
export function computed(fn, dependencies = [], comparator = eq) {
|
export function computed(fn, dependencies = [], comparator = eq) {
|
||||||
const subscribers = new Set();
|
const subscribers = new Set();
|
||||||
const dependents = new Set();
|
const dependents = new Set();
|
||||||
@ -23,7 +25,7 @@ export function computed(fn, dependencies = [], comparator = eq) {
|
|||||||
if (isDirty) {
|
if (isDirty) {
|
||||||
const newVal = fn.apply(null, dependencies.map(runParam));
|
const newVal = fn.apply(null, dependencies.map(runParam));
|
||||||
isDirty = false;
|
isDirty = false;
|
||||||
if (!comparator(newVal, val)) {
|
if (!comparator(val, newVal)) {
|
||||||
val = newVal;
|
val = newVal;
|
||||||
subscribers.forEach(s => s(val));
|
subscribers.forEach(s => s(val));
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user