reactronic 0.92.25006 → 0.92.25007
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -18
- package/build/dist/source/ReactiveSystem.d.ts +3 -5
- package/build/dist/source/ReactiveSystem.js +18 -36
- package/build/dist/source/Ref.js +2 -2
- package/build/dist/source/api.d.ts +2 -1
- package/build/dist/source/api.js +2 -1
- package/build/dist/source/core/ReactiveNode.js +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,23 +13,28 @@ Reactronic is an experimental JavaScript library that provides
|
|
|
13
13
|
[transactional reactive](https://blog.nezaboodka.com/post/2019/593-modern-database-should-natively-support-transactionally-reactive-programming)
|
|
14
14
|
state management in a Web application.
|
|
15
15
|
|
|
16
|
-
Transactional reactivity means that state changes are
|
|
17
|
-
isolated data snapshot and then, once
|
|
18
|
-
**consistently propagated** to
|
|
19
|
-
(re)rendering. All
|
|
16
|
+
Transactional reactivity means that state changes are
|
|
17
|
+
being made in an isolated data snapshot and then, once
|
|
18
|
+
atomically applied, are **consistently propagated** to
|
|
19
|
+
corresponding visual components for (re)rendering. All
|
|
20
|
+
that is done in automatic, seamless, and fine-grained
|
|
20
21
|
way. Reactronic **takes full care of tracking dependencies**
|
|
21
|
-
between visual components (observers) and state
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
- **
|
|
28
|
-
|
|
29
|
-
- **
|
|
30
|
-
|
|
31
|
-
- **
|
|
32
|
-
|
|
22
|
+
between visual components (observers) and state
|
|
23
|
+
(observable objects).
|
|
24
|
+
|
|
25
|
+
Transactional reactivity is based on four fundamental
|
|
26
|
+
concepts:
|
|
27
|
+
|
|
28
|
+
- **Observable Objects** - a set of objects that store
|
|
29
|
+
data of an application (state);
|
|
30
|
+
- **Atomic Action** - a function that makes changes in
|
|
31
|
+
observable objects in atomic way ("all or nothing");
|
|
32
|
+
- **Reactive Process** - recurrent and automatic
|
|
33
|
+
(re-)execution of a function in response to changes
|
|
34
|
+
made by atomic actions;
|
|
35
|
+
- **Cached Result** - result value of a function that
|
|
36
|
+
is remembered and, if the becomes obsolete, causes
|
|
37
|
+
its function to re-execute on-demand.
|
|
33
38
|
|
|
34
39
|
Demo application built with Reactronic: https://nevod.io/#/playground.
|
|
35
40
|
Source code of the demo: https://gitlab.com/nezaboodka/nevod.web.public/-/blob/master/README.md.
|
|
@@ -215,7 +220,8 @@ class Component<P> extends React.Component<P> {
|
|
|
215
220
|
} // EnsureUpToDate is subscribed to render
|
|
216
221
|
|
|
217
222
|
shouldComponentUpdate(): boolean {
|
|
218
|
-
|
|
223
|
+
const r = ReactiveSystem.getController(this.render)
|
|
224
|
+
return !r.isUpToDate
|
|
219
225
|
}
|
|
220
226
|
|
|
221
227
|
componentDidMount(): void {
|
|
@@ -224,7 +230,7 @@ class Component<P> extends React.Component<P> {
|
|
|
224
230
|
}
|
|
225
231
|
|
|
226
232
|
componentWillUnmount(): void {
|
|
227
|
-
atomicAction(
|
|
233
|
+
atomicAction(ReactiveSystem.dispose, this)
|
|
228
234
|
}
|
|
229
235
|
}
|
|
230
236
|
```
|
|
@@ -17,16 +17,14 @@ export declare class ReactiveSystem {
|
|
|
17
17
|
static getLoggingHint<T extends object>(obj: T, full?: boolean): string | undefined;
|
|
18
18
|
static setProfilingMode(isOn: boolean, options?: Partial<ProfilingOptions>): void;
|
|
19
19
|
}
|
|
20
|
+
export declare function atomically<T>(func: F<T>, ...args: any[]): T;
|
|
21
|
+
export declare function atomically<T>(options: SnapshotOptions, func: F<T>, ...args: any[]): T;
|
|
20
22
|
export declare function nonreactive<T>(func: F<T>, ...args: any[]): T;
|
|
21
|
-
export declare function nonreactive2<T>(options: SnapshotOptions, func: F<T>, ...args: any[]): T;
|
|
22
|
-
export declare function nonreactive2<T>(func: F<T>, ...args: any[]): T;
|
|
23
23
|
export declare function sensitive<T>(sensitivity: boolean, func: F<T>, ...args: any[]): T;
|
|
24
24
|
export declare function contextually<T>(p: Promise<T>): Promise<T>;
|
|
25
|
-
export declare function atomicAction<T>(func: F<T>, ...args: any[]): T;
|
|
26
|
-
export declare function atomicAction<T>(options: SnapshotOptions, func: F<T>, ...args: any[]): T;
|
|
27
|
-
export declare function atomicAction(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
28
25
|
export declare function unobservable(proto: object, prop: PropertyKey): any;
|
|
29
26
|
export declare function observable(proto: object, prop: PropertyKey): any;
|
|
27
|
+
export declare function atomicAction(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
30
28
|
export declare function reactiveProcess(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
31
29
|
export declare function cachedResult(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
32
30
|
export declare function options(value: Partial<MemberOptions>): F<any>;
|
|
@@ -22,53 +22,28 @@ export class ReactiveSystem {
|
|
|
22
22
|
static getLoggingHint(obj, full = false) { return ObjectHandle.getHint(obj, full); }
|
|
23
23
|
static setProfilingMode(isOn, options) { Mvcc.setProfilingMode(isOn, options); }
|
|
24
24
|
}
|
|
25
|
-
export function
|
|
26
|
-
return OperationImpl.proceedWithinGivenLaunch(undefined, func, ...args);
|
|
27
|
-
}
|
|
28
|
-
export function nonreactive2(p1, p2, p3) {
|
|
29
|
-
if (p1 instanceof Function) {
|
|
30
|
-
return OperationImpl.proceedWithinGivenLaunch(undefined, () => {
|
|
31
|
-
if (p2 !== undefined)
|
|
32
|
-
return Transaction.run(null, p1, ...p2);
|
|
33
|
-
else
|
|
34
|
-
return Transaction.run(null, p1);
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
return OperationImpl.proceedWithinGivenLaunch(undefined, () => {
|
|
39
|
-
if (p3 !== undefined)
|
|
40
|
-
return Transaction.run(p1, p2, ...p3);
|
|
41
|
-
else
|
|
42
|
-
return Transaction.run(p1, p2);
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
export function sensitive(sensitivity, func, ...args) {
|
|
47
|
-
return Mvcc.sensitive(sensitivity, func, ...args);
|
|
48
|
-
}
|
|
49
|
-
export function contextually(p) {
|
|
50
|
-
throw new Error("not implemented yet");
|
|
51
|
-
}
|
|
52
|
-
export function atomicAction(p1, p2, p3) {
|
|
25
|
+
export function atomically(p1, p2, p3) {
|
|
53
26
|
if (p1 instanceof Function) {
|
|
54
27
|
if (p2 !== undefined)
|
|
55
28
|
return Transaction.run(null, p1, ...p2);
|
|
56
29
|
else
|
|
57
30
|
return Transaction.run(null, p1);
|
|
58
31
|
}
|
|
59
|
-
else
|
|
32
|
+
else {
|
|
60
33
|
if (p3 !== undefined)
|
|
61
34
|
return Transaction.run(p1, p2, ...p3);
|
|
62
35
|
else
|
|
63
36
|
return Transaction.run(p1, p2);
|
|
64
37
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
38
|
+
}
|
|
39
|
+
export function nonreactive(func, ...args) {
|
|
40
|
+
return OperationImpl.proceedWithinGivenLaunch(undefined, func, ...args);
|
|
41
|
+
}
|
|
42
|
+
export function sensitive(sensitivity, func, ...args) {
|
|
43
|
+
return Mvcc.sensitive(sensitivity, func, ...args);
|
|
44
|
+
}
|
|
45
|
+
export function contextually(p) {
|
|
46
|
+
throw new Error("not implemented yet");
|
|
72
47
|
}
|
|
73
48
|
export function unobservable(proto, prop) {
|
|
74
49
|
return Mvcc.decorateData(false, proto, prop);
|
|
@@ -76,6 +51,13 @@ export function unobservable(proto, prop) {
|
|
|
76
51
|
export function observable(proto, prop) {
|
|
77
52
|
return Mvcc.decorateData(true, proto, prop);
|
|
78
53
|
}
|
|
54
|
+
export function atomicAction(proto, prop, pd) {
|
|
55
|
+
const opts = {
|
|
56
|
+
kind: Kind.atomicAction,
|
|
57
|
+
isolation: Isolation.joinToCurrentTransaction,
|
|
58
|
+
};
|
|
59
|
+
return Mvcc.decorateOperation(true, atomicAction, opts, proto, prop, pd);
|
|
60
|
+
}
|
|
79
61
|
export function reactiveProcess(proto, prop, pd) {
|
|
80
62
|
const opts = {
|
|
81
63
|
kind: Kind.reactiveProcess,
|
package/build/dist/source/Ref.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { atomically, nonreactive } from "./ReactiveSystem.js";
|
|
2
2
|
export function refs(owner) {
|
|
3
3
|
return new Proxy(owner, RefGettingProxy);
|
|
4
4
|
}
|
|
@@ -52,7 +52,7 @@ export class ToggleRef extends Ref {
|
|
|
52
52
|
toggle() {
|
|
53
53
|
const o = this.owner;
|
|
54
54
|
const p = this.name;
|
|
55
|
-
|
|
55
|
+
atomically({ hint: `toggle ${o.constructor.name}.${p}` }, () => {
|
|
56
56
|
const v = o[p];
|
|
57
57
|
const isOn = v === this.valueOn || (v instanceof Ref && this.valueOn instanceof Ref &&
|
|
58
58
|
Ref.sameRefs(v, this.valueOn));
|
|
@@ -16,7 +16,8 @@ export { Changeset } from "./core/Changeset.js";
|
|
|
16
16
|
export { Transaction } from "./core/Transaction.js";
|
|
17
17
|
export { Indicator } from "./core/Indicator.js";
|
|
18
18
|
export { Journal } from "./core/Journal.js";
|
|
19
|
-
export {
|
|
19
|
+
export { atomically, nonreactive, sensitive, contextually } from "./ReactiveSystem.js";
|
|
20
|
+
export { ReactiveSystem, observable, unobservable, atomicAction, reactiveProcess, cachedResult, options } from "./ReactiveSystem.js";
|
|
20
21
|
export { ReactiveProcess } from "./Reaction.js";
|
|
21
22
|
export { ReactiveNode, Mode, Priority, BaseDriver, ReactiveNodeVariable } from "./core/ReactiveNode.js";
|
|
22
23
|
export type { Script, ScriptAsync, Handler, ReactiveNodeDecl, ReactiveNodeDriver, ReactiveNodeContext } from "./core/ReactiveNode.js";
|
package/build/dist/source/api.js
CHANGED
|
@@ -12,7 +12,8 @@ export { Changeset } from "./core/Changeset.js";
|
|
|
12
12
|
export { Transaction } from "./core/Transaction.js";
|
|
13
13
|
export { Indicator } from "./core/Indicator.js";
|
|
14
14
|
export { Journal } from "./core/Journal.js";
|
|
15
|
-
export {
|
|
15
|
+
export { atomically, nonreactive, sensitive, contextually } from "./ReactiveSystem.js";
|
|
16
|
+
export { ReactiveSystem, observable, unobservable, atomicAction, reactiveProcess, cachedResult, options } from "./ReactiveSystem.js";
|
|
16
17
|
export { ReactiveProcess } from "./Reaction.js";
|
|
17
18
|
export { ReactiveNode, Mode, Priority, BaseDriver, ReactiveNodeVariable } from "./core/ReactiveNode.js";
|
|
18
19
|
export { Clock } from "./Clock.js";
|
|
@@ -22,7 +22,7 @@ import { emitLetters, getCallerInfo, proceedSyncOrAsync } from "../util/Utils.js
|
|
|
22
22
|
import { Isolation, Reentrance } from "../Options.js";
|
|
23
23
|
import { ObservableObject } from "../core/Mvcc.js";
|
|
24
24
|
import { Transaction } from "../core/Transaction.js";
|
|
25
|
-
import { ReactiveSystem, options, unobservable, reactiveProcess,
|
|
25
|
+
import { ReactiveSystem, options, unobservable, reactiveProcess, atomically, nonreactive } from "../ReactiveSystem.js";
|
|
26
26
|
export var Mode;
|
|
27
27
|
(function (Mode) {
|
|
28
28
|
Mode[Mode["default"] = 0] = "default";
|
|
@@ -339,7 +339,7 @@ class ReactiveNodeImpl extends ReactiveNode {
|
|
|
339
339
|
node.outer = owner;
|
|
340
340
|
else
|
|
341
341
|
node.outer = owner.outer;
|
|
342
|
-
|
|
342
|
+
atomically({ isolation: Isolation.joinAsNestedTransaction }, () => {
|
|
343
343
|
const ctx = node.context;
|
|
344
344
|
if (ctx) {
|
|
345
345
|
ctx.variable = variable;
|
|
@@ -546,7 +546,7 @@ function triggerFinalization(slot, isLeader, individual) {
|
|
|
546
546
|
else
|
|
547
547
|
gFirstToDispose = gLastToDispose = slot;
|
|
548
548
|
if (gFirstToDispose === slot)
|
|
549
|
-
|
|
549
|
+
atomically({ isolation: Isolation.disjoinForInternalDisposal, hint: `runDisposalLoop(initiator=${slot.instance.key})` }, () => {
|
|
550
550
|
void runDisposalLoop().then(NOP, error => console.log(error));
|
|
551
551
|
});
|
|
552
552
|
}
|