@dvashim/store 1.3.0 → 1.4.0
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 +61 -0
- package/dist/ComputedStore.d.ts +13 -0
- package/dist/ComputedStore.d.ts.map +1 -0
- package/dist/ComputedStore.js +52 -0
- package/dist/ComputedStore.js.map +1 -0
- package/dist/Store.d.ts +2 -5
- package/dist/Store.d.ts.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -103,6 +103,52 @@ const unsubscribe = count$.subscribe((state, prevState) => {
|
|
|
103
103
|
unsubscribe()
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
+
### `ComputedStore`
|
|
107
|
+
|
|
108
|
+
A read-only reactive store that derives its value from a source store using a selector. Automatically updates when the source changes. Accepts any `SourceStore<T>` (including `Store` or another `ComputedStore`) as its source.
|
|
109
|
+
|
|
110
|
+
> **Note:** `ComputedStore` is not yet re-exported from the barrel. Import it directly:
|
|
111
|
+
>
|
|
112
|
+
> ```ts
|
|
113
|
+
> import { ComputedStore } from '@dvashim/store/ComputedStore'
|
|
114
|
+
> ```
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
const todos$ = createStore([
|
|
118
|
+
{ text: 'Buy milk', done: true },
|
|
119
|
+
{ text: 'Walk dog', done: false },
|
|
120
|
+
])
|
|
121
|
+
|
|
122
|
+
const remaining$ = new ComputedStore(todos$, (todos) =>
|
|
123
|
+
todos.filter((t) => !t.done).length
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
remaining$.get() // 1
|
|
127
|
+
remaining$.subscribe((count, prev) => console.log(`${prev} → ${count}`))
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### Chaining
|
|
131
|
+
|
|
132
|
+
`ComputedStore` implements `SourceStore<U>`, so it can be used as the source for another `ComputedStore`.
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
const count$ = new ComputedStore(todos$, (todos) => todos.length)
|
|
136
|
+
const label$ = new ComputedStore(count$, (n) => `${n} items`)
|
|
137
|
+
label$.get() // "2 items"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
#### `computed.connect()` / `computed.disconnect()`
|
|
141
|
+
|
|
142
|
+
Control the subscription to the source store. After `disconnect()`, the derived value stops updating and `get()` returns the last known value. Call `connect()` to resume.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
remaining$.disconnect()
|
|
146
|
+
remaining$.isConnected // false
|
|
147
|
+
|
|
148
|
+
remaining$.connect()
|
|
149
|
+
remaining$.isConnected // true
|
|
150
|
+
```
|
|
151
|
+
|
|
106
152
|
### `useStore(store, selector?)`
|
|
107
153
|
|
|
108
154
|
React hook that subscribes a component to a store.
|
|
@@ -127,6 +173,21 @@ function UserName() {
|
|
|
127
173
|
}
|
|
128
174
|
```
|
|
129
175
|
|
|
176
|
+
### Types
|
|
177
|
+
|
|
178
|
+
The following types are exported from the package:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import type { Selector, Subscriber, UpdateOptions, SourceStore } from '@dvashim/store'
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
| Type | Definition |
|
|
185
|
+
| ---- | ---------- |
|
|
186
|
+
| `Selector<T, U>` | `(state: T) => U` |
|
|
187
|
+
| `Subscriber<T>` | `(state: T, prevState: T) => void` |
|
|
188
|
+
| `UpdateOptions` | `{ force?: boolean }` |
|
|
189
|
+
| `SourceStore<T>` | `{ get(): T; subscribe(fn: Subscriber<T>): () => void }` — shared interface implemented by both `Store` and `ComputedStore` |
|
|
190
|
+
|
|
130
191
|
## Patterns
|
|
131
192
|
|
|
132
193
|
### Shared stores across components
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Selector, SourceStore, Subscriber } from './types';
|
|
2
|
+
export declare class ComputedStore<T, U> implements SourceStore<U> {
|
|
3
|
+
#private;
|
|
4
|
+
constructor(source: SourceStore<T>, selector: Selector<T, U>);
|
|
5
|
+
connect(): void;
|
|
6
|
+
disconnect(): void;
|
|
7
|
+
get isConnected(): boolean;
|
|
8
|
+
protected get source(): SourceStore<T>;
|
|
9
|
+
protected get selector(): Selector<T, U>;
|
|
10
|
+
get(): U;
|
|
11
|
+
subscribe(fn: Subscriber<U>): () => void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=ComputedStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComputedStore.d.ts","sourceRoot":"","sources":["../src/ComputedStore.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEhE,qBAAa,aAAa,CAAC,CAAC,EAAE,CAAC,CAAE,YAAW,WAAW,CAAC,CAAC,CAAC;;gBAM5C,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;IAO5D,OAAO;IAOP,UAAU;IAKV,IAAI,WAAW,YAEd;IAED,SAAS,KAAK,MAAM,mBAEnB;IAED,SAAS,KAAK,QAAQ,mBAErB;IAED,GAAG;IAIH,SAAS,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;CAG5B"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Store } from './Store';
|
|
2
|
+
export class ComputedStore {
|
|
3
|
+
#source;
|
|
4
|
+
#derived;
|
|
5
|
+
#selector;
|
|
6
|
+
#unsubscribe;
|
|
7
|
+
constructor(source, selector) {
|
|
8
|
+
this.#source = source;
|
|
9
|
+
this.#derived = new Store(selector(source.get()));
|
|
10
|
+
this.#selector = selector;
|
|
11
|
+
this.connect();
|
|
12
|
+
}
|
|
13
|
+
connect() {
|
|
14
|
+
this.disconnect();
|
|
15
|
+
this.#unsubscribe = this.#source.subscribe((state) => {
|
|
16
|
+
this.#derived.set(this.#selector(state));
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
disconnect() {
|
|
20
|
+
this.#unsubscribe?.();
|
|
21
|
+
this.#unsubscribe = undefined;
|
|
22
|
+
}
|
|
23
|
+
get isConnected() {
|
|
24
|
+
return !!this.#unsubscribe;
|
|
25
|
+
}
|
|
26
|
+
get source() {
|
|
27
|
+
return this.#source;
|
|
28
|
+
}
|
|
29
|
+
get selector() {
|
|
30
|
+
return this.#selector;
|
|
31
|
+
}
|
|
32
|
+
get() {
|
|
33
|
+
return this.#derived.get();
|
|
34
|
+
}
|
|
35
|
+
subscribe(fn) {
|
|
36
|
+
return this.#derived.subscribe(fn);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// const s = new Store([1, 2])
|
|
40
|
+
// const len = new ComputedStore(s, (state) => state.length)
|
|
41
|
+
// const lenString = new ComputedStore(len, (state) => `length: ${state}`)
|
|
42
|
+
// const sum = new ComputedStore(s, (state) => state.reduce((a, b) => a + b, 0))
|
|
43
|
+
// console.log(len.get()) // 2
|
|
44
|
+
// console.log(sum.get()) // 3
|
|
45
|
+
// console.log(lenString.get()) // length: 2
|
|
46
|
+
// const len1 = new SubStore(s, (state) => state.length)
|
|
47
|
+
// const lenString1 = new SubStore(len1, (state) => `length: ${state}`)
|
|
48
|
+
// const sum1 = new SubStore(s, (state) => state.reduce((a, b) => a + b, 0))
|
|
49
|
+
// console.log(len1.get()) // 2
|
|
50
|
+
// console.log(sum1.get()) // 3
|
|
51
|
+
// console.log(lenString1.get()) // length: 2
|
|
52
|
+
//# sourceMappingURL=ComputedStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComputedStore.js","sourceRoot":"","sources":["../src/ComputedStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAG/B,MAAM,OAAO,aAAa;IACf,OAAO,CAAgB;IACvB,QAAQ,CAAU;IAClB,SAAS,CAAgB;IAClC,YAAY,CAA2B;IAEvC,YAAY,MAAsB,EAAE,QAAwB;QAC1D,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QACrB,IAAI,CAAC,QAAQ,GAAG,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QACjD,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAA;QACzB,IAAI,CAAC,OAAO,EAAE,CAAA;IAChB,CAAC;IAED,OAAO;QACL,IAAI,CAAC,UAAU,EAAE,CAAA;QACjB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;YACnD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;QAC1C,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,UAAU;QACR,IAAI,CAAC,YAAY,EAAE,EAAE,CAAA;QACrB,IAAI,CAAC,YAAY,GAAG,SAAS,CAAA;IAC/B,CAAC;IAED,IAAI,WAAW;QACb,OAAO,CAAC,CAAC,IAAI,CAAC,YAAY,CAAA;IAC5B,CAAC;IAED,IAAc,MAAM;QAClB,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED,IAAc,QAAQ;QACpB,OAAO,IAAI,CAAC,SAAS,CAAA;IACvB,CAAC;IAED,GAAG;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAA;IAC5B,CAAC;IAED,SAAS,CAAC,EAAiB;QACzB,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;IACpC,CAAC;CACF;AAED,8BAA8B;AAC9B,4DAA4D;AAC5D,0EAA0E;AAC1E,gFAAgF;AAChF,8BAA8B;AAC9B,8BAA8B;AAC9B,4CAA4C;AAE5C,wDAAwD;AACxD,uEAAuE;AACvE,4EAA4E;AAC5E,+BAA+B;AAC/B,+BAA+B;AAC/B,6CAA6C"}
|
package/dist/Store.d.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
type
|
|
1
|
+
import type { SourceStore, Subscriber, UpdateOptions } from './types';
|
|
2
2
|
type Updater<T> = (prevValue: T) => T;
|
|
3
|
-
type UpdateOptions = {
|
|
4
|
-
force?: boolean;
|
|
5
|
-
};
|
|
6
3
|
/**
|
|
7
4
|
* Reactive state container with subscription-based change notification.
|
|
8
5
|
* @typeParam T - The type of the stored state.
|
|
9
6
|
*/
|
|
10
|
-
export declare class Store<T> {
|
|
7
|
+
export declare class Store<T> implements SourceStore<T> {
|
|
11
8
|
#private;
|
|
12
9
|
constructor(initialState: T);
|
|
13
10
|
/**
|
package/dist/Store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Store.d.ts","sourceRoot":"","sources":["../src/Store.ts"],"names":[],"mappings":"AAAA,KAAK,
|
|
1
|
+
{"version":3,"file":"Store.d.ts","sourceRoot":"","sources":["../src/Store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAErE,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,CAAA;AASrC;;;GAGG;AACH,qBAAa,KAAK,CAAC,CAAC,CAAE,YAAW,WAAW,CAAC,CAAC,CAAC;;gBAMjC,YAAY,EAAE,CAAC;IAI3B;;;;OAIG;IACH,SAAS,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAKxC,iCAAiC;IACjC,GAAG,IAAI,CAAC;IAIR;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa;IAKrC;;;;;OAKG;IACH,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa;CA8DpD"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,2 +1,10 @@
|
|
|
1
1
|
export type Selector<T, U> = (state: T) => U;
|
|
2
|
+
export type Subscriber<T> = (state: T, prevState: T) => void;
|
|
3
|
+
export type UpdateOptions = {
|
|
4
|
+
force?: boolean;
|
|
5
|
+
};
|
|
6
|
+
export type SourceStore<T> = {
|
|
7
|
+
get: () => T;
|
|
8
|
+
subscribe: (fn: Subscriber<T>) => () => void;
|
|
9
|
+
};
|
|
2
10
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAA"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAA;AAC5C,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,IAAI,CAAA;AAC5D,MAAM,MAAM,aAAa,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAC/C,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAC3B,GAAG,EAAE,MAAM,CAAC,CAAA;IACZ,SAAS,EAAE,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,CAAA;CAC7C,CAAA"}
|