@fozy-labs/rx-toolkit 0.5.2 → 0.5.3-rc.1
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/dist/common/options/DefaultOptions.d.ts +1 -1
- package/dist/common/options/SharedOptions.d.ts +2 -2
- package/dist/query/api/createOperation.d.ts +2 -2
- package/dist/query/api/createResource.d.ts +2 -2
- package/dist/query/api/createResourceDuplicator.d.ts +2 -2
- package/dist/query/core/Opertation/Operation.d.ts +2 -2
- package/dist/query/core/Opertation/OperationAgent.d.ts +2 -2
- package/dist/query/core/QueriesCache.d.ts +1 -1
- package/dist/query/core/QueriesLifetimeHooks.d.ts +1 -1
- package/dist/query/core/Resource/Resource.d.ts +2 -2
- package/dist/query/core/Resource/ResourceAgent.d.ts +1 -1
- package/dist/query/core/Resource/ResourceDuplicator.d.ts +3 -3
- package/dist/query/core/Resource/ResourceDuplicator.js +8 -6
- package/dist/query/core/Resource/ResourceDuplicatorAgent.d.ts +2 -2
- package/dist/query/core/Resource/ResourceRef.d.ts +1 -1
- package/dist/query/lib/ReactiveCache.d.ts +1 -1
- package/dist/query/react/useResourceAgent.d.ts +3 -3
- package/dist/signals/base/Devtools.d.ts +1 -1
- package/dist/signals/operators/signalize.d.ts +1 -1
- package/dist/signals/signals/Computed.d.ts +3 -3
- package/dist/signals/signals/Computed.js +7 -7
- package/dist/signals/signals/LocalSignal.d.ts +3 -3
- package/dist/signals/signals/LocalSignal.js +5 -5
- package/dist/signals/signals/Signal.d.ts +8 -14
- package/dist/signals/signals/Signal.js +9 -50
- package/dist/signals/signals/State.d.ts +15 -0
- package/dist/signals/signals/State.js +54 -0
- package/dist/signals/signals/index.d.ts +2 -1
- package/dist/signals/signals/index.js +3 -1
- package/docs/signals/README.md +19 -19
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DevtoolsLike } from "
|
|
2
|
-
import { shallowEqual } from "
|
|
1
|
+
import { DevtoolsLike } from "@/common/devtools";
|
|
2
|
+
import { shallowEqual } from "@/common/utils";
|
|
3
3
|
export declare class SharedOptions {
|
|
4
4
|
static DEVTOOLS: DevtoolsLike | null;
|
|
5
5
|
static onQueryError: ((error: unknown) => void) | null;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { OperationCreateOptions, OperationDefinition } from "
|
|
2
|
-
import { Operation } from "
|
|
1
|
+
import type { OperationCreateOptions, OperationDefinition } from "@/query/types";
|
|
2
|
+
import { Operation } from "@/query/core/Opertation/Operation";
|
|
3
3
|
export declare const createOperation: <ARGS, RESULT, SELECTED = never>(options: OperationCreateOptions<OperationDefinition<ARGS, RESULT, SELECTED>>) => Operation<OperationDefinition<ARGS, RESULT, SELECTED>>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { ResourceCreateOptions, ResourceDefinition } from "
|
|
2
|
-
import { Resource } from "
|
|
1
|
+
import type { ResourceCreateOptions, ResourceDefinition } from "@/query/types";
|
|
2
|
+
import { Resource } from "@/query/core/Resource/Resource";
|
|
3
3
|
export declare const createResource: <ARGS, RESULT, SELECTED = never>(options: ResourceCreateOptions<ResourceDefinition<ARGS, RESULT, SELECTED>>) => Resource<ResourceDefinition<ARGS, RESULT, SELECTED>>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DuplicatorOptions, ResourceDuplicator, DuplicatorDefinition } from "
|
|
2
|
-
import { ResourceDefinition } from "
|
|
1
|
+
import { DuplicatorOptions, ResourceDuplicator, DuplicatorDefinition } from "@/query/core/Resource/ResourceDuplicator";
|
|
2
|
+
import { ResourceDefinition } from "@/query/types";
|
|
3
3
|
export declare const createResourceDuplicator: <ARGS, RESULT, SELECTED = never>(options: DuplicatorOptions<DuplicatorDefinition<ResourceDefinition<ARGS, RESULT, SELECTED>>>) => ResourceDuplicator<DuplicatorDefinition<ResourceDefinition<ARGS, RESULT, SELECTED>>>;
|
|
4
4
|
export type ResourceDuplicatorCreateFn<ARGS, RESULT, SELECTED = never> = (options: DuplicatorOptions<DuplicatorDefinition<ResourceDefinition<ARGS, RESULT, SELECTED>>>) => ResourceDuplicator<DuplicatorDefinition<ResourceDefinition<ARGS, RESULT, SELECTED>>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ReactiveCache } from "
|
|
2
|
-
import type { FallbackOnNever, OperationCreateOptions, OperationDefinition, OperationInstance } from "
|
|
1
|
+
import type { ReactiveCache } from "@/query/lib/ReactiveCache";
|
|
2
|
+
import type { FallbackOnNever, OperationCreateOptions, OperationDefinition, OperationInstance } from "@/query/types";
|
|
3
3
|
import { OperationAgent } from "./OperationAgent";
|
|
4
4
|
export type CoreOperationQueryState<D extends OperationDefinition> = {
|
|
5
5
|
arg: D['Args'] | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OperationAgentInstanse, OperationDefinition } from "
|
|
1
|
+
import { OperationAgentInstanse, OperationDefinition } from "@/query/types";
|
|
2
2
|
import type { Operation } from "./Operation";
|
|
3
3
|
export declare class OperationAgent<D extends OperationDefinition> implements OperationAgentInstanse<D> {
|
|
4
4
|
private _operation;
|
|
@@ -9,7 +9,7 @@ export declare class OperationAgent<D extends OperationDefinition> implements Op
|
|
|
9
9
|
isSuccess: boolean;
|
|
10
10
|
isError: boolean;
|
|
11
11
|
error: {} | undefined;
|
|
12
|
-
data: NonNullable<import("
|
|
12
|
+
data: NonNullable<import("@/query/types").FallbackOnNever<D["Selected"], D["Result"]>> | undefined;
|
|
13
13
|
args: D["Args"];
|
|
14
14
|
}>;
|
|
15
15
|
constructor(_operation: Operation<D>);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Subject } from "rxjs";
|
|
2
|
-
import { OnCacheEntryAdded, OnQueryStarted } from "
|
|
2
|
+
import { OnCacheEntryAdded, OnQueryStarted } from "@/query/types";
|
|
3
3
|
type Options<ARGS, DATA> = {
|
|
4
4
|
onCacheEntryAdded?: OnCacheEntryAdded<ARGS, DATA>;
|
|
5
5
|
onQueryStarted?: OnQueryStarted<ARGS, DATA>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ReactiveCache } from "
|
|
2
|
-
import type { ResourceCreateOptions, ResourceDefinition, ResourceInstance, ResourceRefInstanse, ResourceTransaction } from "
|
|
1
|
+
import { ReactiveCache } from "@/query/lib/ReactiveCache";
|
|
2
|
+
import type { ResourceCreateOptions, ResourceDefinition, ResourceInstance, ResourceRefInstanse, ResourceTransaction } from "@/query/types";
|
|
3
3
|
import { ResourceAgent } from "./ResourceAgent";
|
|
4
4
|
export type CoreResourceQueryState<D extends ResourceDefinition> = {
|
|
5
5
|
transactions: ResourceTransaction[] | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ResourceAgentInstance, ResourceDefinition } from "
|
|
1
|
+
import { ResourceAgentInstance, ResourceDefinition } from "@/query/types";
|
|
2
2
|
import type { Resource } from "./Resource";
|
|
3
3
|
export declare class ResourceAgent<D extends ResourceDefinition> implements ResourceAgentInstance<D> {
|
|
4
4
|
private _resource;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ResourceDefinition } from "
|
|
1
|
+
import { ResourceDefinition } from "@/query/types";
|
|
2
2
|
import { CoreResourceQueryState, Resource } from "./Resource";
|
|
3
|
-
import { ReadableSignalLike } from "
|
|
3
|
+
import { ReadableSignalLike } from "@/signals/types";
|
|
4
4
|
import { Observable, Subject } from "rxjs";
|
|
5
5
|
import { ResourceDuplicatorAgent } from "./ResourceDuplicatorAgent";
|
|
6
6
|
export type DuplicatorOptions<D extends DuplicatorDefinition> = {
|
|
@@ -33,7 +33,7 @@ export declare class ResourceDuplicator<D extends DuplicatorDefinition> {
|
|
|
33
33
|
createAgent: () => ResourceDuplicatorAgent<D>;
|
|
34
34
|
/** @deprecated */
|
|
35
35
|
d_init(args: D['ARGS_ITEM'][]): {
|
|
36
|
-
value$: import("
|
|
36
|
+
value$: import("@/signals/types").ComputeFn<State<D>>;
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
export declare class ComputedReactiveCache<T> {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Signal, signalize } from "
|
|
1
|
+
import { Signal, signalize } from "@/signals";
|
|
2
2
|
import { finalize, ReplaySubject, share, Subject, takeUntil, timer } from "rxjs";
|
|
3
3
|
import { ResourceDuplicatorAgent } from "./ResourceDuplicatorAgent";
|
|
4
4
|
export class ResourceDuplicator {
|
|
@@ -47,7 +47,6 @@ export class ResourceDuplicator {
|
|
|
47
47
|
this._resource.initiate(unreleasedArgs);
|
|
48
48
|
}
|
|
49
49
|
const uninitiatedCaches = new Set();
|
|
50
|
-
console.log({ uninitiatedCaches, fis: this._fis });
|
|
51
50
|
args.forEach(arg => {
|
|
52
51
|
const argKey = this._options.getArgKey(arg);
|
|
53
52
|
let fi = this._fis.get(argKey);
|
|
@@ -87,7 +86,9 @@ export class ResourceDuplicator {
|
|
|
87
86
|
fi.k++;
|
|
88
87
|
releasedCaches.add(fi.cache);
|
|
89
88
|
});
|
|
90
|
-
const queryCache =
|
|
89
|
+
const queryCache = unreleasedArgs?.length > 0
|
|
90
|
+
? this._resource.createQueryCache(unreleasedArgs)
|
|
91
|
+
: null;
|
|
91
92
|
unreleasedArgs.forEach(arg => {
|
|
92
93
|
const argKey = this._options.getArgKey(arg);
|
|
93
94
|
let fi = this._fis.get(argKey);
|
|
@@ -101,9 +102,10 @@ export class ResourceDuplicator {
|
|
|
101
102
|
});
|
|
102
103
|
return {
|
|
103
104
|
value$: Signal.compute(() => {
|
|
104
|
-
const itemsAcc = [
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
const itemsAcc = [];
|
|
106
|
+
if (queryCache) {
|
|
107
|
+
itemsAcc.push(queryCache.value$.get());
|
|
108
|
+
}
|
|
107
109
|
for (const rc of releasedCaches) {
|
|
108
110
|
itemsAcc.push(rc.value$.get());
|
|
109
111
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ResourceAgentInstance } from "
|
|
2
|
-
import { ResourceDuplicator, DuplicatorDefinition } from "
|
|
1
|
+
import { ResourceAgentInstance } from "@/query/types";
|
|
2
|
+
import { ResourceDuplicator, DuplicatorDefinition } from "@/query/core/Resource/ResourceDuplicator";
|
|
3
3
|
export declare class ResourceDuplicatorAgent<D extends DuplicatorDefinition> implements ResourceAgentInstance<D['RESOURCE_DEFINITION']> {
|
|
4
4
|
private _resource;
|
|
5
5
|
private _resources$;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ResourceDefinition, ResourceRefInstanse, ResourceTransaction } from "
|
|
1
|
+
import { ResourceDefinition, ResourceRefInstanse, ResourceTransaction } from "@/query/types";
|
|
2
2
|
import { Resource } from "./Resource";
|
|
3
3
|
export declare class ResourceRef<D extends ResourceDefinition> implements ResourceRefInstanse<D> {
|
|
4
4
|
private readonly _resource;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Prettify, ResourceDefinition, ResourceInstance, ResourceQueryState } from "
|
|
2
|
-
import { SKIP } from "
|
|
3
|
-
import { DuplicatorDefinition, ResourceDuplicator } from "
|
|
1
|
+
import { Prettify, ResourceDefinition, ResourceInstance, ResourceQueryState } from "@/query/types";
|
|
2
|
+
import { SKIP } from "@/query/SKIP_TOKEN";
|
|
3
|
+
import { DuplicatorDefinition, ResourceDuplicator } from "@/query/core/Resource/ResourceDuplicator";
|
|
4
4
|
type Result<D extends ResourceDefinition> = Prettify<ResourceQueryState<D>>;
|
|
5
5
|
export declare function useResourceAgent<D extends ResourceDefinition>(res: ResourceInstance<D> | ResourceDuplicator<DuplicatorDefinition<D>>, ...argss: D['Args'] extends void ? [] | [typeof SKIP] : [D['Args'] | typeof SKIP]): Result<D>;
|
|
6
6
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { StateDevtoolsOptions } from "
|
|
1
|
+
import { StateDevtoolsOptions } from "@/common/devtools";
|
|
2
2
|
export declare const Devtools: {
|
|
3
3
|
createState<T>(initialValue: T, optionsDry?: StateDevtoolsOptions): ((newState: T) => void) | null;
|
|
4
4
|
readonly hasDevtools: boolean;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { StateDevtoolsOptions } from "
|
|
2
|
-
import { ComputeFn } from "
|
|
1
|
+
import { StateDevtoolsOptions } from "@/common/devtools";
|
|
2
|
+
import { ComputeFn } from "@/signals/types";
|
|
3
3
|
export declare class Computed<T> {
|
|
4
4
|
private _computeFn;
|
|
5
|
-
private
|
|
5
|
+
private _state$;
|
|
6
6
|
readonly obs: import("rxjs").Observable<T>;
|
|
7
7
|
private _effect;
|
|
8
8
|
/**
|
|
@@ -4,7 +4,7 @@ import { Effect } from "./Effect";
|
|
|
4
4
|
import { Signal } from "./Signal";
|
|
5
5
|
export class Computed {
|
|
6
6
|
_computeFn;
|
|
7
|
-
|
|
7
|
+
_state$;
|
|
8
8
|
obs;
|
|
9
9
|
_effect = null;
|
|
10
10
|
/**
|
|
@@ -18,8 +18,8 @@ export class Computed {
|
|
|
18
18
|
...(typeof options === 'string' ? { name: options } : options),
|
|
19
19
|
_skipValues: [Computed._EMPTY],
|
|
20
20
|
};
|
|
21
|
-
this.
|
|
22
|
-
this.obs = this.
|
|
21
|
+
this._state$ = Signal.state(Computed._EMPTY, lsOptions);
|
|
22
|
+
this.obs = this._state$.obs.pipe(map((value) => {
|
|
23
23
|
if (value === Computed._EMPTY) {
|
|
24
24
|
return this._start();
|
|
25
25
|
}
|
|
@@ -46,7 +46,7 @@ export class Computed {
|
|
|
46
46
|
return this.peek();
|
|
47
47
|
}
|
|
48
48
|
peek() {
|
|
49
|
-
const v = this.
|
|
49
|
+
const v = this._state$.peek();
|
|
50
50
|
if (v === Computed._EMPTY) {
|
|
51
51
|
// Используем кеш для вычисления без создания подписки
|
|
52
52
|
return this._computeCache.getOrCompute(this._computeFn);
|
|
@@ -58,10 +58,10 @@ export class Computed {
|
|
|
58
58
|
this._effect = new Effect(() => {
|
|
59
59
|
if (initialValue === Computed._EMPTY) {
|
|
60
60
|
initialValue = this._computeFn();
|
|
61
|
-
this.
|
|
61
|
+
this._state$.set(initialValue);
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
|
-
this.
|
|
64
|
+
this._state$.set(this._computeFn());
|
|
65
65
|
});
|
|
66
66
|
this._computeCache.clear();
|
|
67
67
|
if (initialValue === Computed._EMPTY) {
|
|
@@ -74,7 +74,7 @@ export class Computed {
|
|
|
74
74
|
this._effect.unsubscribe();
|
|
75
75
|
this._effect = null;
|
|
76
76
|
}
|
|
77
|
-
this.
|
|
77
|
+
this._state$.set(Computed._EMPTY);
|
|
78
78
|
}
|
|
79
79
|
// === static ===
|
|
80
80
|
static _EMPTY = Symbol('empty');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ZodType } from "zod/v4";
|
|
2
2
|
import { Observable } from "rxjs";
|
|
3
|
-
import { SignalFn } from "
|
|
4
|
-
import { StateDevtoolsOptions } from "
|
|
3
|
+
import { SignalFn } from "@/signals/types";
|
|
4
|
+
import { StateDevtoolsOptions } from "@/common/devtools";
|
|
5
5
|
type Options<T> = {
|
|
6
6
|
zodSchema?: ZodType<T>;
|
|
7
7
|
key: string;
|
|
@@ -15,7 +15,7 @@ type Options<T> = {
|
|
|
15
15
|
devtoolsOptions?: StateDevtoolsOptions;
|
|
16
16
|
};
|
|
17
17
|
export declare class LocalSignal<T = string | null | number | undefined> {
|
|
18
|
-
private
|
|
18
|
+
private _state$;
|
|
19
19
|
private _computed;
|
|
20
20
|
private readonly _options;
|
|
21
21
|
readonly obs: Observable<T>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
import { signalize } from "../operators";
|
|
3
|
-
import { Signal } from "./Signal";
|
|
4
3
|
import { Computed } from "./Computed";
|
|
4
|
+
import { State } from "@/signals/signals/State";
|
|
5
5
|
const NONE = Symbol('NONE');
|
|
6
6
|
export class LocalSignal {
|
|
7
|
-
|
|
7
|
+
_state$;
|
|
8
8
|
_computed;
|
|
9
9
|
_options;
|
|
10
10
|
obs;
|
|
@@ -13,10 +13,10 @@ export class LocalSignal {
|
|
|
13
13
|
if (initialValue === NONE) {
|
|
14
14
|
initialValue = options.defaultValue;
|
|
15
15
|
}
|
|
16
|
-
this.
|
|
16
|
+
this._state$ = new State(initialValue, { isDisabled: true });
|
|
17
17
|
const validatorSignal$ = options.validator$ && signalize(options.validator$);
|
|
18
18
|
this._computed = new Computed(() => {
|
|
19
|
-
const value = this.
|
|
19
|
+
const value = this._state$.get();
|
|
20
20
|
if (validatorSignal$) {
|
|
21
21
|
const validator = validatorSignal$.get();
|
|
22
22
|
if (!validator(value)) {
|
|
@@ -33,7 +33,7 @@ export class LocalSignal {
|
|
|
33
33
|
}
|
|
34
34
|
set(value) {
|
|
35
35
|
LocalSignal._setStorageValue(this._options, value);
|
|
36
|
-
this.
|
|
36
|
+
this._state$.set(value);
|
|
37
37
|
}
|
|
38
38
|
peek() {
|
|
39
39
|
return this._computed.peek();
|
|
@@ -1,18 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
private readonly _stateDevtools;
|
|
7
|
-
private _rang;
|
|
8
|
-
protected readonly bs$: BehaviorSubject<T>;
|
|
9
|
-
readonly obs: import("rxjs").Observable<T>;
|
|
1
|
+
import type { StateDevtoolsOptions } from "@/common/devtools";
|
|
2
|
+
import { SignalFn } from "@/signals/types";
|
|
3
|
+
import { Effect, State } from "@/signals/signals";
|
|
4
|
+
export declare class Signal<T> extends State<T> {
|
|
5
|
+
/** @deprecated use `State` instead */
|
|
10
6
|
constructor(initialValue: T, options?: StateDevtoolsOptions);
|
|
11
|
-
|
|
12
|
-
set(value: T): void;
|
|
13
|
-
get(): T;
|
|
14
|
-
private static _finalizationRegistry;
|
|
7
|
+
/** @deprecated use `state` instead */
|
|
15
8
|
static create<T>(initialValue: T, options?: StateDevtoolsOptions): SignalFn<T>;
|
|
16
|
-
static
|
|
9
|
+
static state<T>(initialValue: T, options?: StateDevtoolsOptions): SignalFn<T>;
|
|
10
|
+
static compute<T>(computeFn: () => T, options?: StateDevtoolsOptions): import("@/signals/types").ComputeFn<T>;
|
|
17
11
|
static effect(effectFn: () => void): Effect;
|
|
18
12
|
}
|
|
@@ -1,56 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export class Signal {
|
|
5
|
-
_stateDevtools;
|
|
6
|
-
_rang = 0;
|
|
7
|
-
bs$;
|
|
8
|
-
obs;
|
|
1
|
+
import { Computed, Effect, State } from "@/signals/signals";
|
|
2
|
+
export class Signal extends State {
|
|
3
|
+
/** @deprecated use `State` instead */
|
|
9
4
|
constructor(initialValue, options) {
|
|
10
|
-
|
|
11
|
-
this.obs = this.bs$.asObservable();
|
|
12
|
-
this._stateDevtools = Devtools.createState(initialValue, {
|
|
13
|
-
base: Signal.name,
|
|
14
|
-
...(typeof options === 'string' ? { name: options } : options)
|
|
15
|
-
});
|
|
16
|
-
if (this._stateDevtools) {
|
|
17
|
-
Signal._finalizationRegistry.register(this, this._stateDevtools);
|
|
18
|
-
}
|
|
5
|
+
super(initialValue, options);
|
|
19
6
|
}
|
|
20
|
-
|
|
21
|
-
return this.bs$.getValue();
|
|
22
|
-
}
|
|
23
|
-
set(value) {
|
|
24
|
-
if (value === this.bs$.value) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
Batcher.run(() => {
|
|
28
|
-
this._stateDevtools?.(value);
|
|
29
|
-
this.bs$.next(value);
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
get() {
|
|
33
|
-
DependencyTracker.track({
|
|
34
|
-
getRang: () => this._rang,
|
|
35
|
-
obs: this.obs,
|
|
36
|
-
peek: () => this.peek(),
|
|
37
|
-
});
|
|
38
|
-
return this.bs$.getValue();
|
|
39
|
-
}
|
|
40
|
-
// === static ===
|
|
41
|
-
static _finalizationRegistry = new FinalizationRegistry((heldValue) => {
|
|
42
|
-
heldValue('$COMPLETED');
|
|
43
|
-
});
|
|
7
|
+
/** @deprecated use `state` instead */
|
|
44
8
|
static create(initialValue, options) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
signalFn.peek = () => ls.peek();
|
|
50
|
-
signalFn.set = (value) => ls.set(value);
|
|
51
|
-
signalFn.get = () => ls.get();
|
|
52
|
-
signalFn.obs = ls.obs;
|
|
53
|
-
return signalFn;
|
|
9
|
+
return this.state(initialValue, options);
|
|
10
|
+
}
|
|
11
|
+
static state(initialValue, options) {
|
|
12
|
+
return State.create(initialValue, options);
|
|
54
13
|
}
|
|
55
14
|
static compute(computeFn, options) {
|
|
56
15
|
return Computed.create(computeFn, options);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BehaviorSubject } from "rxjs";
|
|
2
|
+
import { StateDevtoolsOptions } from "@/common/devtools";
|
|
3
|
+
import { SignalFn } from "@/signals/types";
|
|
4
|
+
export declare class State<T> {
|
|
5
|
+
private readonly _stateDevtools;
|
|
6
|
+
private _rang;
|
|
7
|
+
protected readonly bs$: BehaviorSubject<T>;
|
|
8
|
+
readonly obs: import("rxjs").Observable<T>;
|
|
9
|
+
constructor(initialValue: T, options?: StateDevtoolsOptions);
|
|
10
|
+
peek(): T;
|
|
11
|
+
set(value: T): void;
|
|
12
|
+
get(): T;
|
|
13
|
+
private static _finalizationRegistry;
|
|
14
|
+
static create<T>(initialValue: T, options?: StateDevtoolsOptions): SignalFn<T>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { BehaviorSubject } from "rxjs";
|
|
2
|
+
import { Batcher, DependencyTracker, Devtools } from "../base";
|
|
3
|
+
export class State {
|
|
4
|
+
_stateDevtools;
|
|
5
|
+
_rang = 0;
|
|
6
|
+
bs$;
|
|
7
|
+
obs;
|
|
8
|
+
constructor(initialValue, options) {
|
|
9
|
+
this.bs$ = new BehaviorSubject(initialValue);
|
|
10
|
+
this.obs = this.bs$.asObservable();
|
|
11
|
+
this._stateDevtools = Devtools.createState(initialValue, {
|
|
12
|
+
base: State.name,
|
|
13
|
+
...(typeof options === 'string' ? { name: options } : options)
|
|
14
|
+
});
|
|
15
|
+
if (this._stateDevtools) {
|
|
16
|
+
State._finalizationRegistry.register(this, this._stateDevtools);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
peek() {
|
|
20
|
+
return this.bs$.getValue();
|
|
21
|
+
}
|
|
22
|
+
set(value) {
|
|
23
|
+
if (value === this.bs$.value) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
Batcher.run(() => {
|
|
27
|
+
this._stateDevtools?.(value);
|
|
28
|
+
this.bs$.next(value);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
get() {
|
|
32
|
+
DependencyTracker.track({
|
|
33
|
+
getRang: () => this._rang,
|
|
34
|
+
obs: this.obs,
|
|
35
|
+
peek: () => this.peek(),
|
|
36
|
+
});
|
|
37
|
+
return this.bs$.getValue();
|
|
38
|
+
}
|
|
39
|
+
// === static ===
|
|
40
|
+
static _finalizationRegistry = new FinalizationRegistry((heldValue) => {
|
|
41
|
+
heldValue('$COMPLETED');
|
|
42
|
+
});
|
|
43
|
+
static create(initialValue, options) {
|
|
44
|
+
const ls = new State(initialValue, options);
|
|
45
|
+
function signalFn() {
|
|
46
|
+
return ls.get();
|
|
47
|
+
}
|
|
48
|
+
signalFn.peek = () => ls.peek();
|
|
49
|
+
signalFn.set = (value) => ls.set(value);
|
|
50
|
+
signalFn.get = () => ls.get();
|
|
51
|
+
signalFn.obs = ls.obs;
|
|
52
|
+
return signalFn;
|
|
53
|
+
}
|
|
54
|
+
}
|
package/docs/signals/README.md
CHANGED
|
@@ -6,21 +6,21 @@ RxSignals — это реактивная система управления с
|
|
|
6
6
|
|
|
7
7
|
### Реактивность на основе значений
|
|
8
8
|
|
|
9
|
-
Сигналы (`
|
|
10
|
-
|
|
9
|
+
Сигналы (`State`) хранят текущее состояние, а производные сущности (`Computed`, `Effect`) автоматически отслеживают зависимости,
|
|
10
|
+
применяя кеширование на основе *значений*. Это приводит к тому, что в отличие от классического RxJS-подхода,
|
|
11
11
|
где каждое `next()` — это событие, в RxSignals важен именно факт *изменения значения*.
|
|
12
12
|
|
|
13
|
-
###
|
|
13
|
+
### State
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
База для создания реактивных сигналов с изменяемым состоянием.
|
|
16
16
|
|
|
17
17
|
**Пример использования:**
|
|
18
18
|
|
|
19
19
|
```typescript
|
|
20
20
|
import { Signal } from '@fozy-labs/rx-toolkit';
|
|
21
21
|
|
|
22
|
-
const name = Signal.
|
|
23
|
-
const age = Signal.
|
|
22
|
+
const name = Signal.state('John');
|
|
23
|
+
const age = Signal.state(25);
|
|
24
24
|
|
|
25
25
|
// Чтение значения (с отслеживанием зависимостей)
|
|
26
26
|
console.log(name()); // "John"
|
|
@@ -53,8 +53,8 @@ subscription.unsubscribe();
|
|
|
53
53
|
```typescript
|
|
54
54
|
import { Signal } from '@fozy-labs/rx-toolkit';
|
|
55
55
|
|
|
56
|
-
const firstName = Signal.
|
|
57
|
-
const lastName = Signal.
|
|
56
|
+
const firstName = Signal.state('John');
|
|
57
|
+
const lastName = Signal.state('Doe');
|
|
58
58
|
|
|
59
59
|
const fullName = Signal.compute(() => `${firstName()} ${lastName()}`);
|
|
60
60
|
|
|
@@ -81,8 +81,8 @@ fullName.obs.subscribe(name => console.log(name));
|
|
|
81
81
|
```typescript
|
|
82
82
|
import { Signal } from '@fozy-labs/rx-toolkit';
|
|
83
83
|
|
|
84
|
-
const count = Signal.
|
|
85
|
-
const message = Signal.
|
|
84
|
+
const count = Signal.state(0);
|
|
85
|
+
const message = Signal.state('Hello');
|
|
86
86
|
|
|
87
87
|
const effect = Signal.effect(() => {
|
|
88
88
|
// Выведет: "Hello: 0" при инициализации
|
|
@@ -117,13 +117,13 @@ const effect = Signal.effect(() => {
|
|
|
117
117
|
RxSignals поддерживает как функциональный, так и классовый стили создания сигналов, позволяя выбрать подход в зависимости от предпочтений и архитектуры приложения.
|
|
118
118
|
#### Функциональный стиль (рекомендуемый)
|
|
119
119
|
|
|
120
|
-
Используйте статические методы `Signal.
|
|
120
|
+
Используйте статические методы `Signal.state`,`Signal.compute` и `Signal.effect` для создания сигналов.
|
|
121
121
|
Этот стиль лаконичен, похож на SolidJS и подходит для большинства случаев:
|
|
122
122
|
|
|
123
123
|
```tszz
|
|
124
124
|
import { Signal } from '@fozy-labs/rx-toolkit';
|
|
125
125
|
|
|
126
|
-
const count = Signal.
|
|
126
|
+
const count = Signal.state(0);
|
|
127
127
|
const doubled = Signal.compute(() => count() * 2);
|
|
128
128
|
const logEffect = Signal.effect(() => console.log(doubled()));
|
|
129
129
|
```
|
|
@@ -135,9 +135,9 @@ const logEffect = Signal.effect(() => console.log(doubled()));
|
|
|
135
135
|
учтите, что вызов `()` недоступен и нужно использовать `get()`:
|
|
136
136
|
|
|
137
137
|
```ts
|
|
138
|
-
import {
|
|
138
|
+
import { State, Computed, Effect } from '@fozy-labs/rx-toolkit';
|
|
139
139
|
|
|
140
|
-
const count = new
|
|
140
|
+
const count = new State(0);
|
|
141
141
|
const doubled = new Computed(() => count.get() * 2);
|
|
142
142
|
const logEffect = new Effect(() => console.log(doubled.get()));
|
|
143
143
|
```
|
|
@@ -227,8 +227,8 @@ RxSignals автоматически группирует множественн
|
|
|
227
227
|
- Предсказуемый порядок выполнения эффектов
|
|
228
228
|
|
|
229
229
|
```typescript
|
|
230
|
-
const a = Signal.
|
|
231
|
-
const b = Signal.
|
|
230
|
+
const a = Signal.state(1);
|
|
231
|
+
const b = Signal.state(2);
|
|
232
232
|
const sum = Signal.compute(() => a() + b());
|
|
233
233
|
|
|
234
234
|
new Effect(() => {
|
|
@@ -251,7 +251,7 @@ Batcher.run(() => {
|
|
|
251
251
|
import { filter, take, debounceTime } from 'rxjs';
|
|
252
252
|
import { Signal, Computed, signalize } from '@fozy-labs/rx-toolkit';
|
|
253
253
|
|
|
254
|
-
const clicks = Signal.
|
|
254
|
+
const clicks = Signal.state(0);
|
|
255
255
|
|
|
256
256
|
// Используем RxJS операторы
|
|
257
257
|
const tenClicks$ = clicks.obs.pipe(
|
|
@@ -282,10 +282,10 @@ const doubled = Signal.compute(() => debouncedClicks$() * 2);
|
|
|
282
282
|
import { Signal } from '@fozy-labs/rx-toolkit';
|
|
283
283
|
|
|
284
284
|
// С именем для devtools
|
|
285
|
-
const count$ = Signal.
|
|
285
|
+
const count$ = Signal.state(0, 'counter');
|
|
286
286
|
|
|
287
287
|
// Или с расширенными опциями
|
|
288
|
-
const user$ = Signal.
|
|
288
|
+
const user$ = Signal.state(null, {
|
|
289
289
|
isDisabled: false, // Отключить отслеживание в devtools
|
|
290
290
|
});
|
|
291
291
|
```
|