Rename observable to prop(erty) to distinguish from TC39
This commit is contained in:
parent
8f73b59339
commit
3b84cacbaa
@ -6,7 +6,7 @@ These are my personal projects.
|
|||||||
|
|
||||||
## [FRP tools](./packages/frptools/README.md)
|
## [FRP tools](./packages/frptools/README.md)
|
||||||
|
|
||||||
Observable and computed value stores designed to work together for storing real state and derived
|
Observable property and computed value stores designed to work together for storing real and derived
|
||||||
state.
|
state.
|
||||||
|
|
||||||
## [Portal](./packages/portal/README.md)
|
## [Portal](./packages/portal/README.md)
|
||||||
|
|||||||
@ -1,21 +1,13 @@
|
|||||||
# FRP tools
|
# FRP tools
|
||||||
|
|
||||||
Observer and Computed value stores designed to work together for storing real state and derived
|
Property and Computed value stores designed to work together for storing real and derived state.
|
||||||
state.
|
|
||||||
|
|
||||||
# [observable](./src/observable.js)
|
# [property](./src/property.js)
|
||||||
|
|
||||||
`observable` is a simple value store that can report when its value changes. It is good for wrapping
|
A `property` is a simple value store that can report when its value changes. It is good for wrapping
|
||||||
external props passed into a component so compute types can dependent on them. It can also be used
|
external values passed into a component so compute types can dependent on them and only recompute
|
||||||
to receive events such as _window.onresize_ to always provide the current viewport size.
|
when these values change. It can also be used to receive events such as _window.onresize_ to always
|
||||||
|
provide the current viewport size.
|
||||||
NOTE: Javascript has a proposal for a thing called an
|
|
||||||
[Observable](https://github.com/tc39/proposal-observable). This is not an implementation of that.
|
|
||||||
They do serve similar functions (provide a way to communicate when a value changes) but the tc39
|
|
||||||
proposal is more about event input sources and can communicate errors and be extended. This
|
|
||||||
implementation is designed to be as small and simple as possible. Extending it is done via
|
|
||||||
[Computed] instances depending on them. I may rename `observable` to `property` in a future major
|
|
||||||
release to avoid this confusion.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@ -24,7 +16,7 @@ release to avoid this confusion.
|
|||||||
Creates and sets initial value to `true`
|
Creates and sets initial value to `true`
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const inViewport = observable(true);
|
const inViewport = prop(true);
|
||||||
```
|
```
|
||||||
|
|
||||||
### Read
|
### Read
|
||||||
@ -48,15 +40,15 @@ inViewport(false);
|
|||||||
|
|
||||||
### Subscribe to changes
|
### Subscribe to changes
|
||||||
|
|
||||||
Call the `subscribe` method with a callback that will be called when the observable is changed to a
|
Call the `subscribe` method with a callback that will be called when the property value changes. The
|
||||||
different value. The returned function can be called to unsubscribe from the observable. When called
|
returned function can be called to unsubscribe from the property. When called it will provide the
|
||||||
it will provide the count of remaining subscriptions.
|
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.
|
inViewport.unsubscribeAll(); // Call unsubscribeAll to remove child property/computed subscriptions.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Provide a comparator for complex types
|
### Provide a comparator for complex types
|
||||||
@ -74,13 +66,13 @@ function setEquals(a, b) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const a = observable(new Set([1, 2]), setEquals);
|
const a = prop(new Set([1, 2]), setEquals);
|
||||||
```
|
```
|
||||||
|
|
||||||
# [computed](./src/computed.js)
|
# [computed](./src/computed.js)
|
||||||
|
|
||||||
`computed` is a functional store that depends on the values of observables or other computeds. They
|
`computed` is a functional store that depends on the values of properties or other computeds. They
|
||||||
derive value from observables rather than store value and hence cannot be set directly.
|
derive value from properties rather than store value and hence cannot be set directly.
|
||||||
|
|
||||||
## Behavior
|
## Behavior
|
||||||
|
|
||||||
@ -95,7 +87,7 @@ is set, otherwise it just return the stored result from the last time it compute
|
|||||||
```js
|
```js
|
||||||
const showDialog = computed(
|
const showDialog = computed(
|
||||||
(inVP, shouldShow) => inVP && shouldShow, // computation function
|
(inVP, shouldShow) => inVP && shouldShow, // computation function
|
||||||
[inViewport, shouldShow] // array of dependencies, can be either observable or computed
|
[inViewport, shouldShow] // array of dependencies, can be either a property or computed
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -112,7 +104,7 @@ Call it to receive the stored value, recomputing if necessary.
|
|||||||
### Subscribe to changes
|
### Subscribe to changes
|
||||||
|
|
||||||
Call the subscribe method with a callback that will be called when the computed result changes to a
|
Call the subscribe method with a callback that will be called when the computed result changes to a
|
||||||
different value. The returned function can be called to unsubscribe from the observable. When called
|
different value. The returned function can be called to unsubscribe from the property. When called
|
||||||
it will provide the count of remaining subscriptions.
|
it will provide the count of remaining subscriptions.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@ -125,8 +117,8 @@ changes. This could negatively performance if it depends on multiple values that
|
|||||||
and the computation function is non-trivial. For example:
|
and the computation function is non-trivial. For example:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const inViewport = observable(false);
|
const inViewport = prop(false);
|
||||||
const shouldShow = observable(false);
|
const shouldShow = prop(false);
|
||||||
|
|
||||||
const showDialog = computed((inVP, shouldShow) => inVP && shouldShow, [inViewport, shouldShow]);
|
const showDialog = computed((inVP, shouldShow) => inVP && shouldShow, [inViewport, shouldShow]);
|
||||||
|
|
||||||
@ -142,7 +134,7 @@ 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.detach(); // Call detach to remove this computed from the logic tree.
|
||||||
showDialog.unsubscribeAll(); // Call unsubscribeAll to remove child observables/computeds.
|
showDialog.unsubscribeAll(); // Call unsubscribeAll to remove child property/computed subscriptions.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Provide a comparator for complex types
|
### Provide a comparator for complex types
|
||||||
@ -164,25 +156,26 @@ function _intersection(a, b) {
|
|||||||
return new Set([...a].filter(x => b.has(x)));
|
return new Set([...a].filter(x => b.has(x)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const a = observable(new Set([1, 2]), setEquals);
|
const a = prop(new Set([1, 2]), setEquals);
|
||||||
const b = observable(new Set([2, 3]), setEquals);
|
const b = prop(new Set([2, 3]), setEquals);
|
||||||
const intersection = computed(_intersection, [a, b], setEquals);
|
const intersection = computed(_intersection, [a, b], setEquals);
|
||||||
```
|
```
|
||||||
|
|
||||||
# [bundle](./src/bundle.js)
|
# [bundle](./src/bundle.js)
|
||||||
|
|
||||||
`bundle` is a wrapper around a group of `observables` for the purpose of applying changes to all of
|
`bundle` is a wrapper around a group of properties for the purpose of applying changes to all of
|
||||||
them at once without having to trigger a subscription that may depend on more than observable in the
|
them at once without having to trigger a subscription that may depend on more than property in the
|
||||||
group.
|
group.
|
||||||
|
|
||||||
Another way to think of a `bundle` is an `observable` that takes an object and exposes the
|
Another way to think of a `bundle` is a `property` that takes an object and exposes the object's
|
||||||
properties as individual observables.
|
properties as individual `property` instances.
|
||||||
|
|
||||||
## Behavior
|
## Behavior
|
||||||
|
|
||||||
A `bundle` wraps observables to intercept dependency hooks in such a way that updating all
|
A `bundle` wraps properties to intercept dependency hooks in such a way that updating all `property`
|
||||||
observables can happen at once before any downstream `computeds` are evaluated. A bundle returns a
|
instances can happen at once before any downstream `computed` instances are evaluated. A bundle
|
||||||
function that can be called with an object to set values for the mapped member observables.
|
returns a function that can be called with an object to set values for the mapped member `property`
|
||||||
|
instances.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@ -190,14 +183,14 @@ function that can be called with an object to set values for the mapped member o
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const layoutEventBundle = bundle({
|
const layoutEventBundle = bundle({
|
||||||
width: observable(1),
|
width: prop(1),
|
||||||
height: observable(2)
|
height: prop(2)
|
||||||
});
|
});
|
||||||
const ratio = computed((a, b) => a / b, [layoutEventBundle.width, layoutEventBundle.height]);
|
const ratio = computed((a, b) => a / b, [layoutEventBundle.width, layoutEventBundle.height]);
|
||||||
ratio.subscribe(render);
|
ratio.subscribe(render);
|
||||||
```
|
```
|
||||||
|
|
||||||
### Change Member Observables atomically
|
### Change Member Properties atomically
|
||||||
|
|
||||||
```js
|
```js
|
||||||
layoutEventBundle({ width: 640, height: 480 });
|
layoutEventBundle({ width: 640, height: 480 });
|
||||||
@ -207,11 +200,11 @@ layoutEventBundle({ width: 640, height: 480 });
|
|||||||
change. But bundle allows both values to change and `ratio` will only be evaluated once and `render`
|
change. But bundle allows both values to change and `ratio` will only be evaluated once and `render`
|
||||||
called once.
|
called once.
|
||||||
|
|
||||||
### Change Member Observables individually
|
### Change Member Properties individually
|
||||||
|
|
||||||
```js
|
```js
|
||||||
layoutEventBundle.width(640);
|
layoutEventBundle.width(640);
|
||||||
layoutEventBundle.height(480);
|
layoutEventBundle.height(480);
|
||||||
```
|
```
|
||||||
|
|
||||||
The observables exposed by the bundle can also be updated apart from their grouping.
|
The properties exposed by the bundle can also be updated apart from their grouping.
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "frptools",
|
"name": "frptools",
|
||||||
"version": "1.2.0",
|
"version": "2.0.0",
|
||||||
"description": "Observable and Computed data streams",
|
"description": "Observable Property and Computed data streams",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"jsnext:main": "src/index.js",
|
"jsnext:main": "src/index.js",
|
||||||
"files": ["dist", "lib", "src"],
|
"files": ["dist", "lib", "src"],
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
const { observable, computed, bundle } = require('../lib/index.js');
|
const { prop, computed, bundle } = require('../lib/index.js');
|
||||||
|
|
||||||
describe('bundle', () => {
|
describe('bundle', () => {
|
||||||
const methods = {
|
const methods = {
|
||||||
@ -13,10 +13,10 @@ describe('bundle', () => {
|
|||||||
spyOn(methods, 'getVal').and.callThrough();
|
spyOn(methods, 'getVal').and.callThrough();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('bundles observable changes together', () => {
|
it('bundles property changes together', () => {
|
||||||
const a = bundle({
|
const a = bundle({
|
||||||
a: observable(0),
|
a: prop(0),
|
||||||
b: observable(10)
|
b: prop(10)
|
||||||
});
|
});
|
||||||
const b = computed(methods.square, [a.a]);
|
const b = computed(methods.square, [a.a]);
|
||||||
const c = computed(methods.add, [a.a, a.b]);
|
const c = computed(methods.add, [a.a, a.b]);
|
||||||
@ -47,8 +47,8 @@ describe('bundle', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('unbundled changes are less efficient', () => {
|
it('unbundled changes are less efficient', () => {
|
||||||
const a = observable(0);
|
const a = prop(0);
|
||||||
const _b = observable(10);
|
const _b = prop(10);
|
||||||
const b = computed(methods.square, [a]);
|
const b = computed(methods.square, [a]);
|
||||||
const c = computed(methods.add, [a, _b]);
|
const c = computed(methods.add, [a, _b]);
|
||||||
|
|
||||||
@ -80,8 +80,8 @@ describe('bundle', () => {
|
|||||||
|
|
||||||
it('allows individual members to be updated', () => {
|
it('allows individual members to be updated', () => {
|
||||||
const a = bundle({
|
const a = bundle({
|
||||||
a: observable(0),
|
a: prop(0),
|
||||||
b: observable(10)
|
b: prop(10)
|
||||||
});
|
});
|
||||||
const b = computed(methods.square, [a.a]);
|
const b = computed(methods.square, [a.a]);
|
||||||
const c = computed(methods.add, [a.a, a.b]);
|
const c = computed(methods.add, [a.a, a.b]);
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
const { observable, computed } = require('../lib/index.js');
|
const { prop, computed } = require('../lib/index.js');
|
||||||
|
|
||||||
describe('computed', () => {
|
describe('computed', () => {
|
||||||
const add = (a, b) => a + b;
|
const add = (a, b) => a + b;
|
||||||
const square = a => a * a;
|
const square = a => a * a;
|
||||||
|
|
||||||
it('returns the value computed from its dependencies', () => {
|
it('returns the value computed from its dependencies', () => {
|
||||||
const a = observable(0);
|
const a = prop(0);
|
||||||
const b = computed(square, [a]);
|
const b = computed(square, [a]);
|
||||||
const c = computed(add, [a, b]);
|
const c = computed(add, [a, b]);
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ describe('computed', () => {
|
|||||||
it('only computes when called', () => {
|
it('only computes when called', () => {
|
||||||
let runCount = 0;
|
let runCount = 0;
|
||||||
let currentValue = 1;
|
let currentValue = 1;
|
||||||
const a = observable(0);
|
const a = prop(0);
|
||||||
const b = computed(
|
const b = computed(
|
||||||
val => {
|
val => {
|
||||||
runCount += 1;
|
runCount += 1;
|
||||||
@ -59,7 +59,7 @@ describe('computed', () => {
|
|||||||
let runCount = 0;
|
let runCount = 0;
|
||||||
let subRunCount = 0;
|
let subRunCount = 0;
|
||||||
let currentValue = 1;
|
let currentValue = 1;
|
||||||
const a = observable(0);
|
const a = prop(0);
|
||||||
const b = computed(
|
const b = computed(
|
||||||
val => {
|
val => {
|
||||||
runCount += 1;
|
runCount += 1;
|
||||||
@ -99,7 +99,7 @@ describe('computed', () => {
|
|||||||
let runCount = 0;
|
let runCount = 0;
|
||||||
let subRunCount = 0;
|
let subRunCount = 0;
|
||||||
let currentValue = 1;
|
let currentValue = 1;
|
||||||
const a = observable(0);
|
const a = prop(0);
|
||||||
const b = computed(
|
const b = computed(
|
||||||
val => {
|
val => {
|
||||||
runCount += 1;
|
runCount += 1;
|
||||||
@ -142,7 +142,7 @@ describe('computed', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('can be detached', () => {
|
it('can be detached', () => {
|
||||||
const a = observable(2);
|
const a = prop(2);
|
||||||
const b = computed(square, [a]);
|
const b = computed(square, [a]);
|
||||||
const c = computed(add, [a, b]);
|
const c = computed(add, [a, b]);
|
||||||
|
|
||||||
@ -173,8 +173,8 @@ describe('computed', () => {
|
|||||||
return new Set([...a].filter(x => b.has(x)));
|
return new Set([...a].filter(x => b.has(x)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const a = observable(new Set([1, 2]), setEquals);
|
const a = prop(new Set([1, 2]), setEquals);
|
||||||
const b = observable(new Set([2, 3]), setEquals);
|
const b = prop(new Set([2, 3]), setEquals);
|
||||||
const ABintersection = computed(intersection, [a, b], setEquals);
|
const ABintersection = computed(intersection, [a, b], setEquals);
|
||||||
|
|
||||||
expect(runCount).toEqual(0);
|
expect(runCount).toEqual(0);
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
const { observable } = require('../lib/index.js');
|
const { prop } = require('../lib/index.js');
|
||||||
|
|
||||||
describe('observable', () => {
|
describe('A property', () => {
|
||||||
it('returns its initialized value', () => {
|
it('returns its initialized value', () => {
|
||||||
const a = observable(true);
|
const a = prop(true);
|
||||||
expect(a()).toEqual(true);
|
expect(a()).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns its set value', () => {
|
it('returns its set value', () => {
|
||||||
const a = observable();
|
const a = prop();
|
||||||
expect(a()).toEqual(undefined);
|
expect(a()).toEqual(undefined);
|
||||||
expect(a(true)).toEqual(true);
|
expect(a(true)).toEqual(true);
|
||||||
});
|
});
|
||||||
@ -15,7 +15,7 @@ describe('observable', () => {
|
|||||||
it('returns notifies dependents of updates', () => {
|
it('returns notifies dependents of updates', () => {
|
||||||
let runCount = 0;
|
let runCount = 0;
|
||||||
let currentValue = 1;
|
let currentValue = 1;
|
||||||
const a = observable();
|
const a = prop();
|
||||||
a.subscribe(val => {
|
a.subscribe(val => {
|
||||||
runCount += 1;
|
runCount += 1;
|
||||||
expect(val).toEqual(currentValue);
|
expect(val).toEqual(currentValue);
|
||||||
@ -39,7 +39,7 @@ describe('observable', () => {
|
|||||||
it('honors cancelled subscriptions', () => {
|
it('honors cancelled subscriptions', () => {
|
||||||
let runCount = 0;
|
let runCount = 0;
|
||||||
let currentValue = 1;
|
let currentValue = 1;
|
||||||
const a = observable();
|
const a = prop();
|
||||||
const cancelSubscription = a.subscribe(val => {
|
const cancelSubscription = a.subscribe(val => {
|
||||||
runCount += 1;
|
runCount += 1;
|
||||||
expect(val).toEqual(currentValue);
|
expect(val).toEqual(currentValue);
|
||||||
@ -74,7 +74,7 @@ describe('observable', () => {
|
|||||||
|
|
||||||
let runCount = 0;
|
let runCount = 0;
|
||||||
|
|
||||||
const a = observable(new Set([1, 2]), setEquals);
|
const a = prop(new Set([1, 2]), setEquals);
|
||||||
a.subscribe(() => (runCount += 1));
|
a.subscribe(() => (runCount += 1));
|
||||||
expect([...a()]).toEqual([1, 2]);
|
expect([...a()]).toEqual([1, 2]);
|
||||||
expect(runCount).toEqual(0);
|
expect(runCount).toEqual(0);
|
||||||
@ -1,4 +1,4 @@
|
|||||||
export function bundle(observables) {
|
export function bundle(props) {
|
||||||
const activeSubscribers = new Set();
|
const activeSubscribers = new Set();
|
||||||
let activeUpdate = false;
|
let activeUpdate = false;
|
||||||
|
|
||||||
@ -6,9 +6,9 @@ export function bundle(observables) {
|
|||||||
const result = {};
|
const result = {};
|
||||||
activeUpdate = true;
|
activeUpdate = true;
|
||||||
Object.keys(values)
|
Object.keys(values)
|
||||||
.filter(k => typeof observables[k] === 'function')
|
.filter(k => typeof props[k] === 'function')
|
||||||
.forEach(k => {
|
.forEach(k => {
|
||||||
result[k] = observables[k](values[k]);
|
result[k] = props[k](values[k]);
|
||||||
});
|
});
|
||||||
|
|
||||||
const subscribers = Array.from(activeSubscribers);
|
const subscribers = Array.from(activeSubscribers);
|
||||||
@ -32,8 +32,8 @@ export function bundle(observables) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.keys(observables).forEach(k => {
|
Object.keys(props).forEach(k => {
|
||||||
const obs = observables[k];
|
const obs = props[k];
|
||||||
|
|
||||||
accessor[k] = obs;
|
accessor[k] = obs;
|
||||||
obs._d = subscriptionFactory(obs._d);
|
obs._d = subscriptionFactory(obs._d);
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
export { observable } from './observable';
|
export { prop } from './property';
|
||||||
export { computed } from './computed';
|
export { computed } from './computed';
|
||||||
export { bundle } from './bundle';
|
export { bundle } from './bundle';
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { eq } from './util.js';
|
import { eq } from './util.js';
|
||||||
|
|
||||||
export function observable(store, comparator = eq) {
|
export function prop(store, comparator = eq) {
|
||||||
const subscribers = new Set();
|
const subscribers = new Set();
|
||||||
|
|
||||||
const accessor = function _observable(newVal) {
|
const accessor = function _prop(newVal) {
|
||||||
if (newVal !== undefined && !comparator(store, newVal)) {
|
if (newVal !== undefined && !comparator(store, newVal)) {
|
||||||
store = newVal;
|
store = newVal;
|
||||||
subscribers.forEach(s => s(store));
|
subscribers.forEach(s => s(store));
|
||||||
@ -16,7 +16,7 @@
|
|||||||
"domvm": "~3.2.1",
|
"domvm": "~3.2.1",
|
||||||
"exif-parser": "~0.1.9",
|
"exif-parser": "~0.1.9",
|
||||||
"extract-text-webpack-plugin": "^3.0.2",
|
"extract-text-webpack-plugin": "^3.0.2",
|
||||||
"frptools": "1.2.0",
|
"frptools": "2.0.0",
|
||||||
"pica": "~2.0.8",
|
"pica": "~2.0.8",
|
||||||
"pouchdb-adapter-http": "~6.3.4",
|
"pouchdb-adapter-http": "~6.3.4",
|
||||||
"pouchdb-adapter-idb": "~6.3.4",
|
"pouchdb-adapter-idb": "~6.3.4",
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { defineView, defineElement as el } from 'domvm';
|
import { defineView, defineElement as el } from 'domvm';
|
||||||
import { observable, computed } from 'frptools';
|
import { prop, computed } from 'frptools';
|
||||||
|
|
||||||
import * as image from '../data/image.js';
|
import * as image from '../data/image.js';
|
||||||
|
|
||||||
export function ImageView(vm, model) {
|
export function ImageView(vm, model) {
|
||||||
const { addTag } = model;
|
const { addTag } = model;
|
||||||
const imageData = observable(null);
|
const imageData = prop(null);
|
||||||
let imageId = null;
|
let imageId = null;
|
||||||
|
|
||||||
function onAddTag(image_id) {
|
function onAddTag(image_id) {
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { extractID } from './conversion.js';
|
|||||||
import { equals } from './set.js';
|
import { equals } from './set.js';
|
||||||
|
|
||||||
export function pouchDocArrayComparator(a, b) {
|
export function pouchDocArrayComparator(a, b) {
|
||||||
if (!Array.isArray(b)) {
|
if (!Array.isArray(a)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const aIDs = a.map(extractID);
|
const aIDs = a.map(extractID);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { observable, computed } from 'frptools';
|
import { prop, computed } from 'frptools';
|
||||||
import { matchesSelector } from 'pouchdb-selector-core';
|
import { matchesSelector } from 'pouchdb-selector-core';
|
||||||
|
|
||||||
import { getDatabase } from '../services/db.js';
|
import { getDatabase } from '../services/db.js';
|
||||||
@ -54,8 +54,8 @@ export function LiveArray(db, selector, watcher) {
|
|||||||
const _watcher = watcher || Watcher(db, selector);
|
const _watcher = watcher || Watcher(db, selector);
|
||||||
let changeSub = null;
|
let changeSub = null;
|
||||||
|
|
||||||
const ready = observable(false);
|
const ready = prop(false);
|
||||||
const data = observable({ docs: [] });
|
const data = prop({ docs: [] });
|
||||||
const docs = computed(r => r.docs, [data], pouchDocArrayComparator);
|
const docs = computed(r => r.docs, [data], pouchDocArrayComparator);
|
||||||
|
|
||||||
const idSet = () => docs().reduce((acc, d) => acc.add(d._id), new Set());
|
const idSet = () => docs().reduce((acc, d) => acc.add(d._id), new Set());
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user