floppy-disk 2.16.0 → 3.0.0-experimental.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/README.md +11 -31
- package/esm/index.d.ts +2 -2
- package/esm/index.js +2 -2
- package/esm/react/create-bi-direction-query.d.ts +1 -1
- package/esm/react/create-mutation.d.ts +1 -1
- package/esm/react/create-store.d.ts +14 -27
- package/esm/react/create-store.js +3 -3
- package/esm/react/create-stores.d.ts +15 -31
- package/esm/react/create-stores.js +4 -30
- package/esm/{fetcher.js → vanilla/fetcher.js} +1 -1
- package/{lib/store.d.ts → esm/vanilla/init-store.d.ts} +7 -7
- package/esm/{store.js → vanilla/init-store.js} +18 -18
- package/lib/index.d.ts +2 -2
- package/lib/index.js +2 -2
- package/lib/react/create-bi-direction-query.d.ts +1 -1
- package/lib/react/create-mutation.d.ts +1 -1
- package/lib/react/create-store.d.ts +14 -27
- package/lib/react/create-store.js +4 -4
- package/lib/react/create-stores.d.ts +15 -31
- package/lib/react/create-stores.js +5 -31
- package/lib/{fetcher.js → vanilla/fetcher.js} +1 -1
- package/{esm/store.d.ts → lib/vanilla/init-store.d.ts} +7 -7
- package/lib/{store.js → vanilla/init-store.js} +18 -18
- package/package.json +1 -1
- /package/esm/{fetcher.d.ts → vanilla/fetcher.d.ts} +0 -0
- /package/lib/{fetcher.d.ts → vanilla/fetcher.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ import { createQuery, createMutation } from 'floppy-disk'; // 9.7 kB (gzipped: 3
|
|
|
30
30
|
|
|
31
31
|
- **Create Store**
|
|
32
32
|
- Get/set store inside/outside component
|
|
33
|
-
- Very simple way to customize the reactivity (state update subscription)
|
|
33
|
+
- Very simple way to customize the reactivity (a.k.a. state update subscription)
|
|
34
34
|
- Support middleware
|
|
35
35
|
- Set state interception
|
|
36
36
|
- Store event (`onSubscribe`, `onUnsubscribe`, etc.)
|
|
@@ -112,12 +112,12 @@ Use the hook anywhere, no providers are needed.
|
|
|
112
112
|
|
|
113
113
|
```jsx
|
|
114
114
|
function Cat() {
|
|
115
|
-
const age = useCatStore(
|
|
115
|
+
const { age } = useCatStore((state) => [state.age]);
|
|
116
116
|
return <div>Cat's age: {age}</div>;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
function Control() {
|
|
120
|
-
const increaseAge = useCatStore(
|
|
120
|
+
const { increaseAge } = useCatStore((state) => [state.increaseAge]);
|
|
121
121
|
return <button onClick={increaseAge}>Increase cat's age</button>;
|
|
122
122
|
}
|
|
123
123
|
```
|
|
@@ -130,36 +130,26 @@ Control the reactivity. The concept is same as useEffect dependency array.
|
|
|
130
130
|
function YourComponent() {
|
|
131
131
|
const { age, isSleeping } = useCatStore();
|
|
132
132
|
// Will re-render every state change ^
|
|
133
|
+
...
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
function YourComponent() {
|
|
136
137
|
const { age, isSleeping } = useCatStore((state) => [state.isSleeping]);
|
|
137
138
|
// Will only re-render when isSleeping is updated ^
|
|
138
139
|
// Update on age won't cause re-render this component
|
|
140
|
+
...
|
|
139
141
|
}
|
|
140
142
|
|
|
141
143
|
function YourComponent() {
|
|
142
144
|
const { age, isSleeping } = useCatStore((state) => [state.age, state.isSleeping]);
|
|
143
145
|
// Will re-render when age or isSleeping is updated ^
|
|
146
|
+
...
|
|
144
147
|
}
|
|
145
148
|
|
|
146
149
|
function YourComponent() {
|
|
147
150
|
const { age, isSleeping } = useCatStore((state) => [state.age > 3]);
|
|
148
151
|
// Will only re-render when (age>3) is updated
|
|
149
|
-
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
Even simpler way, after version `2.13.0`, we can use store's object key:
|
|
153
|
-
|
|
154
|
-
```jsx
|
|
155
|
-
function YourComponent() {
|
|
156
|
-
const age = useCatStore('age');
|
|
157
|
-
// Will only re-render when age is updated
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function YourComponent() {
|
|
161
|
-
const age = useCatStore('isSleeping');
|
|
162
|
-
// Will only re-render when isSleeping is updated
|
|
152
|
+
...
|
|
163
153
|
}
|
|
164
154
|
```
|
|
165
155
|
|
|
@@ -198,7 +188,7 @@ const decreaseAgeSilently = () => {
|
|
|
198
188
|
};
|
|
199
189
|
// 👇 Will not re-render
|
|
200
190
|
function Cat() {
|
|
201
|
-
const age = useCatStore(
|
|
191
|
+
const { age } = useCatStore((state) => [state.age]);
|
|
202
192
|
return <div>Cat's age: {age}</div>;
|
|
203
193
|
}
|
|
204
194
|
```
|
|
@@ -268,7 +258,7 @@ Prevent re-render using `Watch`.
|
|
|
268
258
|
|
|
269
259
|
```jsx
|
|
270
260
|
function CatPage() {
|
|
271
|
-
const age = useCatStore(
|
|
261
|
+
const { age } = useCatStore((state) => [state.age]);
|
|
272
262
|
// If age changed, this component will re-render which will cause
|
|
273
263
|
// HeavyComponent1 & HeavyComponent2 to be re-rendered as well.
|
|
274
264
|
return (
|
|
@@ -286,8 +276,8 @@ function CatPageOptimized() {
|
|
|
286
276
|
<main>
|
|
287
277
|
<HeavyComponent1 />
|
|
288
278
|
<useCatStore.Watch
|
|
289
|
-
selectDeps=
|
|
290
|
-
render={(age) => {
|
|
279
|
+
selectDeps={(state) => [state.age]}
|
|
280
|
+
render={({ age }) => {
|
|
291
281
|
return <div>Cat's age: {age}</div>;
|
|
292
282
|
}}
|
|
293
283
|
/>
|
|
@@ -338,20 +328,11 @@ function Parent() {
|
|
|
338
328
|
|
|
339
329
|
function CatAge() {
|
|
340
330
|
const { age } = useCatStoreContext()((state) => [state.age]);
|
|
341
|
-
|
|
342
|
-
// Shorthand after v1.13.0:
|
|
343
|
-
// const age = useCatStoreContext()('age');
|
|
344
|
-
|
|
345
331
|
return <div>Age: {age}</div>;
|
|
346
332
|
}
|
|
347
|
-
|
|
348
333
|
function CatIsSleeping() {
|
|
349
334
|
const useCatStore = useCatStoreContext();
|
|
350
335
|
const { isSleeping } = useCatStore((state) => [state.isSleeping]);
|
|
351
|
-
|
|
352
|
-
// Shorthand after v1.13.0:
|
|
353
|
-
// const isSleeping = useCatStore('isSleeping');
|
|
354
|
-
|
|
355
336
|
return (
|
|
356
337
|
<>
|
|
357
338
|
<div>Is Sleeping: {String(isSleeping)}</div>
|
|
@@ -802,7 +783,6 @@ Don't use conditional reactivity selector.
|
|
|
802
783
|
|
|
803
784
|
```jsx
|
|
804
785
|
function Cat({ isSomething }) {
|
|
805
|
-
const value = useCatStore(isSomething ? 'age' : 'isSleeping'); // ❌
|
|
806
786
|
const { age } = useCatStore(isSomething ? (state) => [state.age] : null); // ❌
|
|
807
787
|
const { age } = useCatStore((state) => (isSomething ? [state.age] : [state.isSleeping])); // ❌
|
|
808
788
|
return <div>Cat's age: {age}</div>;
|
package/esm/index.d.ts
CHANGED
package/esm/index.js
CHANGED
|
@@ -6,7 +6,7 @@ export declare const createBiDirectionQuery: <TKey extends StoreKey = StoreKey,
|
|
|
6
6
|
getNextPageParam: (lastPage: TResponse, index: number, stateBeforeCallQuery: QueryState<TKey, TResponse, TData, TError, TPageParam>) => Maybe<TPageParam>;
|
|
7
7
|
select: (response: TResponse, state: Pick<QueryState<TKey, TResponse, TData, TError, TPageParam>, "data" | "key">, direction: 'prev' | 'next') => TData;
|
|
8
8
|
}) => {
|
|
9
|
-
(
|
|
9
|
+
(...args: [Maybe<TKey>, import("..").SelectDeps<QueryState<TKey, TResponse, TData, TError, TPageParam>>?] | [import("..").SelectDeps<QueryState<TKey, TResponse, TData, TError, TPageParam>>?]): {
|
|
10
10
|
data: (never[] | TData)[number][];
|
|
11
11
|
fetchPrevPage: () => Promise<QueryState<TKey, TResponse, TData, TError, TPageParam>>;
|
|
12
12
|
hasPrevPage: boolean;
|
|
@@ -1,35 +1,22 @@
|
|
|
1
|
-
import { InitStoreOptions, SelectDeps,
|
|
2
|
-
export type WatchProps<T
|
|
3
|
-
selectDeps?:
|
|
4
|
-
render: (state:
|
|
1
|
+
import { InitStoreOptions, SelectDeps, SetStoreState, StoreInitializer, StoreState, Subscribers } from '../vanilla/init-store';
|
|
2
|
+
export type WatchProps<T> = {
|
|
3
|
+
selectDeps?: SelectDeps<T>;
|
|
4
|
+
render: (state: T) => any;
|
|
5
5
|
};
|
|
6
|
-
export type UseStore<T extends
|
|
6
|
+
export type UseStore<T extends StoreState> = {
|
|
7
7
|
/**
|
|
8
|
-
* @param selectDeps
|
|
8
|
+
* @param selectDeps A function that return the dependency array (just like in `useEffect`), to trigger reactivity.
|
|
9
|
+
*
|
|
9
10
|
* Defaults to `undefined` (reactive to all state change) if you didn't set `defaultDeps` on `createStore`.
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
+
* Value of `null` will also make it reactive to all state change.
|
|
12
13
|
*
|
|
13
14
|
* **IMPORTANT NOTE:** `selectDeps` must not be changed after initialization.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```tsx
|
|
17
|
-
* const useMyStore = createStore({
|
|
18
|
-
* foo: 12,
|
|
19
|
-
* bar: true,
|
|
20
|
-
* baz: "z",
|
|
21
|
-
* });
|
|
22
|
-
*
|
|
23
|
-
* const MyComponent = () => {
|
|
24
|
-
* const foo = useMyStore("foo");
|
|
25
|
-
* // Will only re-render if "foo" updated
|
|
26
|
-
* };
|
|
27
|
-
* ```
|
|
28
15
|
*/
|
|
29
|
-
|
|
16
|
+
(selectDeps?: SelectDeps<T>): T;
|
|
30
17
|
get: () => T;
|
|
31
|
-
set: (value:
|
|
32
|
-
subscribe: (fn: (state: T) => void, selectDeps?: SelectDeps<T>
|
|
18
|
+
set: (value: SetStoreState<T>, silent?: boolean) => void;
|
|
19
|
+
subscribe: (fn: (state: T) => void, selectDeps?: SelectDeps<T>) => () => void;
|
|
33
20
|
getSubscribers: () => Subscribers<T>;
|
|
34
21
|
/**
|
|
35
22
|
* ⚛️ (**_Hook_**)
|
|
@@ -40,12 +27,12 @@ export type UseStore<T extends StoreData> = {
|
|
|
40
27
|
* - This is a hook, put it inside of a React component
|
|
41
28
|
* - Put this on the root component or parent component, before any component subscribed!
|
|
42
29
|
*/
|
|
43
|
-
setDefaultValues: (values:
|
|
44
|
-
Watch:
|
|
30
|
+
setDefaultValues: (values: SetStoreState<T>) => void;
|
|
31
|
+
Watch: (props: WatchProps<T>) => any;
|
|
45
32
|
};
|
|
46
33
|
/**
|
|
47
34
|
* @see https://floppy-disk.vercel.app/docs/api#createstore
|
|
48
35
|
*/
|
|
49
|
-
export declare const createStore: <T extends
|
|
36
|
+
export declare const createStore: <T extends StoreState>(initializer: StoreInitializer<T>, options?: InitStoreOptions<T> & {
|
|
50
37
|
defaultDeps?: SelectDeps<T>;
|
|
51
38
|
}) => UseStore<T>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
|
-
import { initStore, } from '../store';
|
|
2
|
+
import { initStore, } from '../vanilla/init-store';
|
|
3
3
|
/**
|
|
4
4
|
* @see https://floppy-disk.vercel.app/docs/api#createstore
|
|
5
5
|
*/
|
|
@@ -13,7 +13,7 @@ export const createStore = (initializer, options = {}) => {
|
|
|
13
13
|
const [state, setState] = useState(get);
|
|
14
14
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
15
15
|
useEffect(() => subscribe(setState, selectDeps), []);
|
|
16
|
-
return
|
|
16
|
+
return state;
|
|
17
17
|
};
|
|
18
18
|
useStore.get = get;
|
|
19
19
|
useStore.set = set;
|
|
@@ -29,7 +29,7 @@ export const createStore = (initializer, options = {}) => {
|
|
|
29
29
|
set(value);
|
|
30
30
|
});
|
|
31
31
|
};
|
|
32
|
-
const Watch = ({ selectDeps = defaultDeps, render
|
|
32
|
+
const Watch = ({ selectDeps = defaultDeps, render }) => {
|
|
33
33
|
const store = useStore(selectDeps);
|
|
34
34
|
return render(store);
|
|
35
35
|
};
|
|
@@ -1,49 +1,33 @@
|
|
|
1
|
-
import { InitStoreOptions, InitStoreReturn, SelectDeps, SetStoreData, StoreData, Subscribers } from '../store';
|
|
2
1
|
import { Maybe } from '../utils';
|
|
2
|
+
import { InitStoreOptions, InitStoreReturn, SelectDeps, SetStoreState, StoreState, Subscribers } from '../vanilla/init-store';
|
|
3
3
|
import { WatchProps } from './create-store';
|
|
4
4
|
export type StoreKey = Record<string, any> | undefined;
|
|
5
|
-
export type StoresInitializer<TKey extends StoreKey = StoreKey, T extends
|
|
5
|
+
export type StoresInitializer<TKey extends StoreKey = StoreKey, T extends StoreState = StoreState> = T | ((api: {
|
|
6
6
|
get: () => T;
|
|
7
|
-
set: (value:
|
|
7
|
+
set: (value: SetStoreState<T>, silent?: boolean) => void;
|
|
8
8
|
key: TKey;
|
|
9
9
|
keyHash: string;
|
|
10
10
|
}) => T);
|
|
11
|
-
export type UseStores<TKey extends StoreKey = StoreKey, T extends
|
|
11
|
+
export type UseStores<TKey extends StoreKey = StoreKey, T extends StoreState = StoreState> = {
|
|
12
12
|
/**
|
|
13
13
|
* @param key (Optional) Store key, an object that will be hashed into a string as a store identifier.
|
|
14
14
|
* No need to memoize the store key.
|
|
15
15
|
*
|
|
16
16
|
* @param selectDeps (Optional) A function that return the dependency array (just like in `useEffect`), to trigger reactivity.
|
|
17
|
+
*
|
|
17
18
|
* Defaults to `undefined` (reactive to all state change) if you didn't set `defaultDeps` on `createStores`.
|
|
18
19
|
*
|
|
19
|
-
*
|
|
20
|
+
* Value of `null` will also make it reactive to all state change.
|
|
20
21
|
*
|
|
21
22
|
* **IMPORTANT NOTE:** `selectDeps` must not be changed after initialization.
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```tsx
|
|
25
|
-
* type StoreKey = { id: string };
|
|
26
|
-
* type StoreData = { foo: number; bar: boolean; baz: string };
|
|
27
|
-
* const useMyStores = createStores<StoreKey, StoreData>({
|
|
28
|
-
* foo: 12,
|
|
29
|
-
* bar: true,
|
|
30
|
-
* baz: "z",
|
|
31
|
-
* });
|
|
32
|
-
*
|
|
33
|
-
* export const MyComponent = () => {
|
|
34
|
-
* const foo = useMyStores({ id: "p1" }, "foo");
|
|
35
|
-
* // Will only re-render if "foo" & store key ("id") updated
|
|
36
|
-
* };
|
|
37
|
-
* ```
|
|
38
23
|
*/
|
|
39
|
-
<
|
|
40
|
-
<K extends SelectDeps<T> | keyof T = SelectDeps<T>>(key: Maybe<TKey>, selectDeps?: K): K extends keyof T ? T[K] : T;
|
|
24
|
+
(...args: [Maybe<TKey>, SelectDeps<T>?] | [SelectDeps<T>?]): T;
|
|
41
25
|
get: (key?: Maybe<TKey>) => T;
|
|
42
26
|
getAll: () => T[];
|
|
43
27
|
getAllWithSubscriber: () => T[];
|
|
44
|
-
set: (key: Maybe<TKey>, value:
|
|
45
|
-
setAll: (value:
|
|
46
|
-
subscribe: (key: Maybe<TKey>, fn: (state: T) => void, selectDeps?: SelectDeps<T>
|
|
28
|
+
set: (key: Maybe<TKey>, value: SetStoreState<T>, silent?: boolean) => void;
|
|
29
|
+
setAll: (value: SetStoreState<T>, silent?: boolean) => void;
|
|
30
|
+
subscribe: (key: Maybe<TKey>, fn: (state: T) => void, selectDeps?: SelectDeps<T>) => () => void;
|
|
47
31
|
getSubscribers: (key: Maybe<TKey>) => Subscribers<T>;
|
|
48
32
|
getStore: (key?: Maybe<TKey>) => InitStoreReturn<T>;
|
|
49
33
|
getStores: () => Map<string, InitStoreReturn<T>>;
|
|
@@ -56,12 +40,12 @@ export type UseStores<TKey extends StoreKey = StoreKey, T extends StoreData = St
|
|
|
56
40
|
* - This is a hook, put it inside of a React component
|
|
57
41
|
* - Put this on the root component or parent component, before any component subscribed!
|
|
58
42
|
*/
|
|
59
|
-
setDefaultValues: (key: Maybe<TKey>, values:
|
|
60
|
-
Watch:
|
|
43
|
+
setDefaultValues: (key: Maybe<TKey>, values: SetStoreState<T>) => void;
|
|
44
|
+
Watch: (props: WatchProps<T> & {
|
|
61
45
|
storeKey?: Maybe<TKey>;
|
|
62
46
|
}) => any;
|
|
63
47
|
};
|
|
64
|
-
export type CreateStoresOptions<TKey extends StoreKey = StoreKey, T extends
|
|
48
|
+
export type CreateStoresOptions<TKey extends StoreKey = StoreKey, T extends StoreState = StoreState> = InitStoreOptions<T> & {
|
|
65
49
|
onBeforeChangeKey?: (nextKey: TKey, prevKey: TKey) => void;
|
|
66
50
|
/**
|
|
67
51
|
* Will be triggered when a single store with a specific key was initialized.
|
|
@@ -70,8 +54,8 @@ export type CreateStoresOptions<TKey extends StoreKey = StoreKey, T extends Stor
|
|
|
70
54
|
defaultDeps?: SelectDeps<T>;
|
|
71
55
|
hashKeyFn?: (obj: TKey) => string;
|
|
72
56
|
};
|
|
73
|
-
export declare const hashStoreKey: (
|
|
57
|
+
export declare const hashStoreKey: (obj?: any) => string;
|
|
74
58
|
/**
|
|
75
59
|
* @see https://floppy-disk.vercel.app/docs/api#createstores
|
|
76
60
|
*/
|
|
77
|
-
export declare const createStores: <TKey extends StoreKey = StoreKey, T extends
|
|
61
|
+
export declare const createStores: <TKey extends StoreKey = StoreKey, T extends StoreState = StoreState>(initializer: StoresInitializer<TKey, T>, options?: CreateStoresOptions<TKey, T>) => UseStores<TKey, T>;
|
|
@@ -1,32 +1,7 @@
|
|
|
1
1
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
-
import { initStore, } from '../store';
|
|
3
2
|
import { getValue, noop } from '../utils';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
};
|
|
7
|
-
const isPlainObject = (value) => {
|
|
8
|
-
if (!hasObjectPrototype(value))
|
|
9
|
-
return false;
|
|
10
|
-
const ctor = value.constructor;
|
|
11
|
-
if (typeof ctor === 'undefined')
|
|
12
|
-
return true;
|
|
13
|
-
const prot = ctor.prototype;
|
|
14
|
-
if (!hasObjectPrototype(prot))
|
|
15
|
-
return false;
|
|
16
|
-
if (!prot.hasOwnProperty('isPrototypeOf'))
|
|
17
|
-
return false;
|
|
18
|
-
return true;
|
|
19
|
-
};
|
|
20
|
-
export const hashStoreKey = (value) =>
|
|
21
|
-
// Copied from: https://github.com/TanStack/query/blob/main/packages/query-core/src/utils.ts
|
|
22
|
-
JSON.stringify(value, (_, val) => isPlainObject(val)
|
|
23
|
-
? Object.keys(val)
|
|
24
|
-
.sort()
|
|
25
|
-
.reduce((result, key) => {
|
|
26
|
-
result[key] = val[key];
|
|
27
|
-
return result;
|
|
28
|
-
}, {})
|
|
29
|
-
: val);
|
|
3
|
+
import { initStore, } from '../vanilla/init-store';
|
|
4
|
+
export const hashStoreKey = (obj) => JSON.stringify(obj, Object.keys(obj).sort());
|
|
30
5
|
/**
|
|
31
6
|
* @see https://floppy-disk.vercel.app/docs/api#createstores
|
|
32
7
|
*/
|
|
@@ -46,7 +21,7 @@ export const createStores = (initializer, options = {}) => {
|
|
|
46
21
|
* **IMPORTANT NOTE:** `selectDeps` function must not be changed after initialization.
|
|
47
22
|
*/
|
|
48
23
|
const useStores = (...args) => {
|
|
49
|
-
const [_key, selectDeps = defaultDeps] = (typeof args[0] === 'function'
|
|
24
|
+
const [_key, selectDeps = defaultDeps] = (typeof args[0] === 'function' ? [{}, args[0]] : args);
|
|
50
25
|
const key = _key || {};
|
|
51
26
|
const keyHash = hashKeyFn(key);
|
|
52
27
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -63,8 +38,7 @@ export const createStores = (initializer, options = {}) => {
|
|
|
63
38
|
}, [keyHash]);
|
|
64
39
|
if (keyHash !== prevKeyHash.current)
|
|
65
40
|
onBeforeChangeKey(key, prevKey.current);
|
|
66
|
-
|
|
67
|
-
return (typeof selectDeps === 'string' ? state[selectDeps] : state);
|
|
41
|
+
return get();
|
|
68
42
|
};
|
|
69
43
|
useStores.get = (key) => {
|
|
70
44
|
const store = getStore(key);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createError, getValue, identityFn } from '
|
|
1
|
+
import { createError, getValue, identityFn } from '../utils';
|
|
2
2
|
const encodeParams = (params) => Object.entries(params)
|
|
3
3
|
.filter(([, value]) => value !== undefined && value !== null)
|
|
4
4
|
.map((kv) => kv.map(encodeURIComponent).join('='))
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Maybe } from '
|
|
2
|
-
export type
|
|
3
|
-
export type
|
|
1
|
+
import { Maybe } from '../utils';
|
|
2
|
+
export type StoreState = Record<string, any>;
|
|
3
|
+
export type SetStoreState<T> = Partial<T> | ((state: T) => Partial<T>);
|
|
4
4
|
export type SelectDeps<T> = ((state: T) => any[]) | undefined | null;
|
|
5
5
|
export type Subscribers<T> = Map<(state: T) => void, SelectDeps<T>>;
|
|
6
6
|
export type StoreInitializer<T> = T | ((api: {
|
|
7
7
|
get: () => T;
|
|
8
|
-
set: (value:
|
|
8
|
+
set: (value: SetStoreState<T>, silent?: boolean) => void;
|
|
9
9
|
}) => T);
|
|
10
10
|
export type StoreEvent<T> = (state: T) => void;
|
|
11
11
|
export type InitStoreOptions<T> = {
|
|
@@ -17,8 +17,8 @@ export type InitStoreOptions<T> = {
|
|
|
17
17
|
};
|
|
18
18
|
export type InitStoreReturn<T> = {
|
|
19
19
|
get: () => T;
|
|
20
|
-
set: (value:
|
|
21
|
-
subscribe: (fn: (state: T) => void, selectDeps?: SelectDeps<T>
|
|
20
|
+
set: (value: SetStoreState<T>, silent?: boolean) => void;
|
|
21
|
+
subscribe: (fn: (state: T) => void, selectDeps?: SelectDeps<T>) => () => void;
|
|
22
22
|
getSubscribers: () => Subscribers<T>;
|
|
23
23
|
};
|
|
24
|
-
export declare const initStore: <T extends
|
|
24
|
+
export declare const initStore: <T extends StoreState>(initializer: StoreInitializer<T>, options?: InitStoreOptions<T>) => InitStoreReturn<T>;
|
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
import { getValue, noop } from '
|
|
1
|
+
import { getValue, noop } from '../utils';
|
|
2
2
|
export const initStore = (initializer, options = {}) => {
|
|
3
3
|
const { intercept, onFirstSubscribe = noop, onSubscribe = noop, onUnsubscribe = noop, onLastUnsubscribe = noop, } = options;
|
|
4
4
|
const subscribers = new Map();
|
|
5
5
|
const getSubscribers = () => subscribers;
|
|
6
|
-
let
|
|
7
|
-
const get = () =>
|
|
6
|
+
let state;
|
|
7
|
+
const get = () => state;
|
|
8
8
|
const set = (value, silent = false) => {
|
|
9
|
-
const
|
|
10
|
-
|
|
9
|
+
const prevState = state;
|
|
10
|
+
state = { ...state, ...getValue(value, state) };
|
|
11
11
|
if (intercept) {
|
|
12
|
-
|
|
12
|
+
state = { ...state, ...intercept(state, prevState) };
|
|
13
13
|
}
|
|
14
14
|
if (silent)
|
|
15
15
|
return;
|
|
16
|
-
const keys = Object.keys(
|
|
16
|
+
const keys = Object.keys(state);
|
|
17
17
|
subscribers.forEach((selectDeps, fn) => {
|
|
18
18
|
if (!selectDeps) {
|
|
19
19
|
for (let i = 0, n = keys.length; i < n; i++) {
|
|
20
|
-
if (
|
|
21
|
-
fn(
|
|
20
|
+
if (prevState[keys[i]] !== state[keys[i]]) {
|
|
21
|
+
fn(state);
|
|
22
22
|
break;
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
|
-
const prevs = selectDeps(
|
|
28
|
-
const nexts = selectDeps(
|
|
27
|
+
const prevs = selectDeps(prevState);
|
|
28
|
+
const nexts = selectDeps(state);
|
|
29
29
|
for (let i = 0, n = prevs.length; i < n; i++) {
|
|
30
30
|
if (prevs[i] !== nexts[i]) {
|
|
31
|
-
fn(
|
|
31
|
+
fn(state);
|
|
32
32
|
break;
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
36
|
};
|
|
37
37
|
const subscribe = (fn, selectDeps) => {
|
|
38
|
-
subscribers.set(fn,
|
|
38
|
+
subscribers.set(fn, selectDeps);
|
|
39
39
|
if (subscribers.size === 1)
|
|
40
|
-
onFirstSubscribe(
|
|
41
|
-
onSubscribe(
|
|
40
|
+
onFirstSubscribe(state);
|
|
41
|
+
onSubscribe(state);
|
|
42
42
|
return () => {
|
|
43
43
|
subscribers.delete(fn);
|
|
44
|
-
onUnsubscribe(
|
|
44
|
+
onUnsubscribe(state);
|
|
45
45
|
if (subscribers.size === 0)
|
|
46
|
-
onLastUnsubscribe(
|
|
46
|
+
onLastUnsubscribe(state);
|
|
47
47
|
};
|
|
48
48
|
};
|
|
49
|
-
|
|
49
|
+
state = getValue(initializer, { get, set });
|
|
50
50
|
return { get, set, subscribe, getSubscribers };
|
|
51
51
|
};
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
-
tslib_1.__exportStar(require("./store"), exports);
|
|
5
|
-
tslib_1.__exportStar(require("./fetcher"), exports);
|
|
4
|
+
tslib_1.__exportStar(require("./vanilla/init-store"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./vanilla/fetcher"), exports);
|
|
6
6
|
tslib_1.__exportStar(require("./react/create-store"), exports);
|
|
7
7
|
tslib_1.__exportStar(require("./react/create-stores"), exports);
|
|
8
8
|
tslib_1.__exportStar(require("./react/create-query"), exports);
|
|
@@ -6,7 +6,7 @@ export declare const createBiDirectionQuery: <TKey extends StoreKey = StoreKey,
|
|
|
6
6
|
getNextPageParam: (lastPage: TResponse, index: number, stateBeforeCallQuery: QueryState<TKey, TResponse, TData, TError, TPageParam>) => Maybe<TPageParam>;
|
|
7
7
|
select: (response: TResponse, state: Pick<QueryState<TKey, TResponse, TData, TError, TPageParam>, "data" | "key">, direction: 'prev' | 'next') => TData;
|
|
8
8
|
}) => {
|
|
9
|
-
(
|
|
9
|
+
(...args: [Maybe<TKey>, import("..").SelectDeps<QueryState<TKey, TResponse, TData, TError, TPageParam>>?] | [import("..").SelectDeps<QueryState<TKey, TResponse, TData, TError, TPageParam>>?]): {
|
|
10
10
|
data: (never[] | TData)[number][];
|
|
11
11
|
fetchPrevPage: () => Promise<QueryState<TKey, TResponse, TData, TError, TPageParam>>;
|
|
12
12
|
hasPrevPage: boolean;
|
|
@@ -1,35 +1,22 @@
|
|
|
1
|
-
import { InitStoreOptions, SelectDeps,
|
|
2
|
-
export type WatchProps<T
|
|
3
|
-
selectDeps?:
|
|
4
|
-
render: (state:
|
|
1
|
+
import { InitStoreOptions, SelectDeps, SetStoreState, StoreInitializer, StoreState, Subscribers } from '../vanilla/init-store';
|
|
2
|
+
export type WatchProps<T> = {
|
|
3
|
+
selectDeps?: SelectDeps<T>;
|
|
4
|
+
render: (state: T) => any;
|
|
5
5
|
};
|
|
6
|
-
export type UseStore<T extends
|
|
6
|
+
export type UseStore<T extends StoreState> = {
|
|
7
7
|
/**
|
|
8
|
-
* @param selectDeps
|
|
8
|
+
* @param selectDeps A function that return the dependency array (just like in `useEffect`), to trigger reactivity.
|
|
9
|
+
*
|
|
9
10
|
* Defaults to `undefined` (reactive to all state change) if you didn't set `defaultDeps` on `createStore`.
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
+
* Value of `null` will also make it reactive to all state change.
|
|
12
13
|
*
|
|
13
14
|
* **IMPORTANT NOTE:** `selectDeps` must not be changed after initialization.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```tsx
|
|
17
|
-
* const useMyStore = createStore({
|
|
18
|
-
* foo: 12,
|
|
19
|
-
* bar: true,
|
|
20
|
-
* baz: "z",
|
|
21
|
-
* });
|
|
22
|
-
*
|
|
23
|
-
* const MyComponent = () => {
|
|
24
|
-
* const foo = useMyStore("foo");
|
|
25
|
-
* // Will only re-render if "foo" updated
|
|
26
|
-
* };
|
|
27
|
-
* ```
|
|
28
15
|
*/
|
|
29
|
-
|
|
16
|
+
(selectDeps?: SelectDeps<T>): T;
|
|
30
17
|
get: () => T;
|
|
31
|
-
set: (value:
|
|
32
|
-
subscribe: (fn: (state: T) => void, selectDeps?: SelectDeps<T>
|
|
18
|
+
set: (value: SetStoreState<T>, silent?: boolean) => void;
|
|
19
|
+
subscribe: (fn: (state: T) => void, selectDeps?: SelectDeps<T>) => () => void;
|
|
33
20
|
getSubscribers: () => Subscribers<T>;
|
|
34
21
|
/**
|
|
35
22
|
* ⚛️ (**_Hook_**)
|
|
@@ -40,12 +27,12 @@ export type UseStore<T extends StoreData> = {
|
|
|
40
27
|
* - This is a hook, put it inside of a React component
|
|
41
28
|
* - Put this on the root component or parent component, before any component subscribed!
|
|
42
29
|
*/
|
|
43
|
-
setDefaultValues: (values:
|
|
44
|
-
Watch:
|
|
30
|
+
setDefaultValues: (values: SetStoreState<T>) => void;
|
|
31
|
+
Watch: (props: WatchProps<T>) => any;
|
|
45
32
|
};
|
|
46
33
|
/**
|
|
47
34
|
* @see https://floppy-disk.vercel.app/docs/api#createstore
|
|
48
35
|
*/
|
|
49
|
-
export declare const createStore: <T extends
|
|
36
|
+
export declare const createStore: <T extends StoreState>(initializer: StoreInitializer<T>, options?: InitStoreOptions<T> & {
|
|
50
37
|
defaultDeps?: SelectDeps<T>;
|
|
51
38
|
}) => UseStore<T>;
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createStore = void 0;
|
|
4
4
|
const react_1 = require("react");
|
|
5
|
-
const
|
|
5
|
+
const init_store_1 = require("../vanilla/init-store");
|
|
6
6
|
/**
|
|
7
7
|
* @see https://floppy-disk.vercel.app/docs/api#createstore
|
|
8
8
|
*/
|
|
9
9
|
const createStore = (initializer, options = {}) => {
|
|
10
|
-
const { get, set, subscribe, getSubscribers } = (0,
|
|
10
|
+
const { get, set, subscribe, getSubscribers } = (0, init_store_1.initStore)(initializer, options);
|
|
11
11
|
const { defaultDeps } = options;
|
|
12
12
|
/**
|
|
13
13
|
* **IMPORTANT NOTE:** `selectDeps` function must not be changed after initialization.
|
|
@@ -16,7 +16,7 @@ const createStore = (initializer, options = {}) => {
|
|
|
16
16
|
const [state, setState] = (0, react_1.useState)(get);
|
|
17
17
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
18
18
|
(0, react_1.useEffect)(() => subscribe(setState, selectDeps), []);
|
|
19
|
-
return
|
|
19
|
+
return state;
|
|
20
20
|
};
|
|
21
21
|
useStore.get = get;
|
|
22
22
|
useStore.set = set;
|
|
@@ -32,7 +32,7 @@ const createStore = (initializer, options = {}) => {
|
|
|
32
32
|
set(value);
|
|
33
33
|
});
|
|
34
34
|
};
|
|
35
|
-
const Watch = ({ selectDeps = defaultDeps, render
|
|
35
|
+
const Watch = ({ selectDeps = defaultDeps, render }) => {
|
|
36
36
|
const store = useStore(selectDeps);
|
|
37
37
|
return render(store);
|
|
38
38
|
};
|
|
@@ -1,49 +1,33 @@
|
|
|
1
|
-
import { InitStoreOptions, InitStoreReturn, SelectDeps, SetStoreData, StoreData, Subscribers } from '../store';
|
|
2
1
|
import { Maybe } from '../utils';
|
|
2
|
+
import { InitStoreOptions, InitStoreReturn, SelectDeps, SetStoreState, StoreState, Subscribers } from '../vanilla/init-store';
|
|
3
3
|
import { WatchProps } from './create-store';
|
|
4
4
|
export type StoreKey = Record<string, any> | undefined;
|
|
5
|
-
export type StoresInitializer<TKey extends StoreKey = StoreKey, T extends
|
|
5
|
+
export type StoresInitializer<TKey extends StoreKey = StoreKey, T extends StoreState = StoreState> = T | ((api: {
|
|
6
6
|
get: () => T;
|
|
7
|
-
set: (value:
|
|
7
|
+
set: (value: SetStoreState<T>, silent?: boolean) => void;
|
|
8
8
|
key: TKey;
|
|
9
9
|
keyHash: string;
|
|
10
10
|
}) => T);
|
|
11
|
-
export type UseStores<TKey extends StoreKey = StoreKey, T extends
|
|
11
|
+
export type UseStores<TKey extends StoreKey = StoreKey, T extends StoreState = StoreState> = {
|
|
12
12
|
/**
|
|
13
13
|
* @param key (Optional) Store key, an object that will be hashed into a string as a store identifier.
|
|
14
14
|
* No need to memoize the store key.
|
|
15
15
|
*
|
|
16
16
|
* @param selectDeps (Optional) A function that return the dependency array (just like in `useEffect`), to trigger reactivity.
|
|
17
|
+
*
|
|
17
18
|
* Defaults to `undefined` (reactive to all state change) if you didn't set `defaultDeps` on `createStores`.
|
|
18
19
|
*
|
|
19
|
-
*
|
|
20
|
+
* Value of `null` will also make it reactive to all state change.
|
|
20
21
|
*
|
|
21
22
|
* **IMPORTANT NOTE:** `selectDeps` must not be changed after initialization.
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```tsx
|
|
25
|
-
* type StoreKey = { id: string };
|
|
26
|
-
* type StoreData = { foo: number; bar: boolean; baz: string };
|
|
27
|
-
* const useMyStores = createStores<StoreKey, StoreData>({
|
|
28
|
-
* foo: 12,
|
|
29
|
-
* bar: true,
|
|
30
|
-
* baz: "z",
|
|
31
|
-
* });
|
|
32
|
-
*
|
|
33
|
-
* export const MyComponent = () => {
|
|
34
|
-
* const foo = useMyStores({ id: "p1" }, "foo");
|
|
35
|
-
* // Will only re-render if "foo" & store key ("id") updated
|
|
36
|
-
* };
|
|
37
|
-
* ```
|
|
38
23
|
*/
|
|
39
|
-
<
|
|
40
|
-
<K extends SelectDeps<T> | keyof T = SelectDeps<T>>(key: Maybe<TKey>, selectDeps?: K): K extends keyof T ? T[K] : T;
|
|
24
|
+
(...args: [Maybe<TKey>, SelectDeps<T>?] | [SelectDeps<T>?]): T;
|
|
41
25
|
get: (key?: Maybe<TKey>) => T;
|
|
42
26
|
getAll: () => T[];
|
|
43
27
|
getAllWithSubscriber: () => T[];
|
|
44
|
-
set: (key: Maybe<TKey>, value:
|
|
45
|
-
setAll: (value:
|
|
46
|
-
subscribe: (key: Maybe<TKey>, fn: (state: T) => void, selectDeps?: SelectDeps<T>
|
|
28
|
+
set: (key: Maybe<TKey>, value: SetStoreState<T>, silent?: boolean) => void;
|
|
29
|
+
setAll: (value: SetStoreState<T>, silent?: boolean) => void;
|
|
30
|
+
subscribe: (key: Maybe<TKey>, fn: (state: T) => void, selectDeps?: SelectDeps<T>) => () => void;
|
|
47
31
|
getSubscribers: (key: Maybe<TKey>) => Subscribers<T>;
|
|
48
32
|
getStore: (key?: Maybe<TKey>) => InitStoreReturn<T>;
|
|
49
33
|
getStores: () => Map<string, InitStoreReturn<T>>;
|
|
@@ -56,12 +40,12 @@ export type UseStores<TKey extends StoreKey = StoreKey, T extends StoreData = St
|
|
|
56
40
|
* - This is a hook, put it inside of a React component
|
|
57
41
|
* - Put this on the root component or parent component, before any component subscribed!
|
|
58
42
|
*/
|
|
59
|
-
setDefaultValues: (key: Maybe<TKey>, values:
|
|
60
|
-
Watch:
|
|
43
|
+
setDefaultValues: (key: Maybe<TKey>, values: SetStoreState<T>) => void;
|
|
44
|
+
Watch: (props: WatchProps<T> & {
|
|
61
45
|
storeKey?: Maybe<TKey>;
|
|
62
46
|
}) => any;
|
|
63
47
|
};
|
|
64
|
-
export type CreateStoresOptions<TKey extends StoreKey = StoreKey, T extends
|
|
48
|
+
export type CreateStoresOptions<TKey extends StoreKey = StoreKey, T extends StoreState = StoreState> = InitStoreOptions<T> & {
|
|
65
49
|
onBeforeChangeKey?: (nextKey: TKey, prevKey: TKey) => void;
|
|
66
50
|
/**
|
|
67
51
|
* Will be triggered when a single store with a specific key was initialized.
|
|
@@ -70,8 +54,8 @@ export type CreateStoresOptions<TKey extends StoreKey = StoreKey, T extends Stor
|
|
|
70
54
|
defaultDeps?: SelectDeps<T>;
|
|
71
55
|
hashKeyFn?: (obj: TKey) => string;
|
|
72
56
|
};
|
|
73
|
-
export declare const hashStoreKey: (
|
|
57
|
+
export declare const hashStoreKey: (obj?: any) => string;
|
|
74
58
|
/**
|
|
75
59
|
* @see https://floppy-disk.vercel.app/docs/api#createstores
|
|
76
60
|
*/
|
|
77
|
-
export declare const createStores: <TKey extends StoreKey = StoreKey, T extends
|
|
61
|
+
export declare const createStores: <TKey extends StoreKey = StoreKey, T extends StoreState = StoreState>(initializer: StoresInitializer<TKey, T>, options?: CreateStoresOptions<TKey, T>) => UseStores<TKey, T>;
|
|
@@ -2,34 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createStores = exports.hashStoreKey = void 0;
|
|
4
4
|
const react_1 = require("react");
|
|
5
|
-
const store_1 = require("../store");
|
|
6
5
|
const utils_1 = require("../utils");
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
};
|
|
10
|
-
const isPlainObject = (value) => {
|
|
11
|
-
if (!hasObjectPrototype(value))
|
|
12
|
-
return false;
|
|
13
|
-
const ctor = value.constructor;
|
|
14
|
-
if (typeof ctor === 'undefined')
|
|
15
|
-
return true;
|
|
16
|
-
const prot = ctor.prototype;
|
|
17
|
-
if (!hasObjectPrototype(prot))
|
|
18
|
-
return false;
|
|
19
|
-
if (!prot.hasOwnProperty('isPrototypeOf'))
|
|
20
|
-
return false;
|
|
21
|
-
return true;
|
|
22
|
-
};
|
|
23
|
-
const hashStoreKey = (value) =>
|
|
24
|
-
// Copied from: https://github.com/TanStack/query/blob/main/packages/query-core/src/utils.ts
|
|
25
|
-
JSON.stringify(value, (_, val) => isPlainObject(val)
|
|
26
|
-
? Object.keys(val)
|
|
27
|
-
.sort()
|
|
28
|
-
.reduce((result, key) => {
|
|
29
|
-
result[key] = val[key];
|
|
30
|
-
return result;
|
|
31
|
-
}, {})
|
|
32
|
-
: val);
|
|
6
|
+
const init_store_1 = require("../vanilla/init-store");
|
|
7
|
+
const hashStoreKey = (obj) => JSON.stringify(obj, Object.keys(obj).sort());
|
|
33
8
|
exports.hashStoreKey = hashStoreKey;
|
|
34
9
|
/**
|
|
35
10
|
* @see https://floppy-disk.vercel.app/docs/api#createstores
|
|
@@ -41,7 +16,7 @@ const createStores = (initializer, options = {}) => {
|
|
|
41
16
|
const key = _key || {};
|
|
42
17
|
const keyHash = hashKeyFn(key);
|
|
43
18
|
if (!stores.has(keyHash)) {
|
|
44
|
-
stores.set(keyHash, (0,
|
|
19
|
+
stores.set(keyHash, (0, init_store_1.initStore)((api) => (0, utils_1.getValue)(initializer, { key, keyHash, ...api }), options));
|
|
45
20
|
onStoreInitialized(key, keyHash);
|
|
46
21
|
}
|
|
47
22
|
return stores.get(keyHash);
|
|
@@ -50,7 +25,7 @@ const createStores = (initializer, options = {}) => {
|
|
|
50
25
|
* **IMPORTANT NOTE:** `selectDeps` function must not be changed after initialization.
|
|
51
26
|
*/
|
|
52
27
|
const useStores = (...args) => {
|
|
53
|
-
const [_key, selectDeps = defaultDeps] = (typeof args[0] === 'function'
|
|
28
|
+
const [_key, selectDeps = defaultDeps] = (typeof args[0] === 'function' ? [{}, args[0]] : args);
|
|
54
29
|
const key = _key || {};
|
|
55
30
|
const keyHash = hashKeyFn(key);
|
|
56
31
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -67,8 +42,7 @@ const createStores = (initializer, options = {}) => {
|
|
|
67
42
|
}, [keyHash]);
|
|
68
43
|
if (keyHash !== prevKeyHash.current)
|
|
69
44
|
onBeforeChangeKey(key, prevKey.current);
|
|
70
|
-
|
|
71
|
-
return (typeof selectDeps === 'string' ? state[selectDeps] : state);
|
|
45
|
+
return get();
|
|
72
46
|
};
|
|
73
47
|
useStores.get = (key) => {
|
|
74
48
|
const store = getStore(key);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.fetcher = void 0;
|
|
4
|
-
const utils_1 = require("
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
5
|
const encodeParams = (params) => Object.entries(params)
|
|
6
6
|
.filter(([, value]) => value !== undefined && value !== null)
|
|
7
7
|
.map((kv) => kv.map(encodeURIComponent).join('='))
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Maybe } from '
|
|
2
|
-
export type
|
|
3
|
-
export type
|
|
1
|
+
import { Maybe } from '../utils';
|
|
2
|
+
export type StoreState = Record<string, any>;
|
|
3
|
+
export type SetStoreState<T> = Partial<T> | ((state: T) => Partial<T>);
|
|
4
4
|
export type SelectDeps<T> = ((state: T) => any[]) | undefined | null;
|
|
5
5
|
export type Subscribers<T> = Map<(state: T) => void, SelectDeps<T>>;
|
|
6
6
|
export type StoreInitializer<T> = T | ((api: {
|
|
7
7
|
get: () => T;
|
|
8
|
-
set: (value:
|
|
8
|
+
set: (value: SetStoreState<T>, silent?: boolean) => void;
|
|
9
9
|
}) => T);
|
|
10
10
|
export type StoreEvent<T> = (state: T) => void;
|
|
11
11
|
export type InitStoreOptions<T> = {
|
|
@@ -17,8 +17,8 @@ export type InitStoreOptions<T> = {
|
|
|
17
17
|
};
|
|
18
18
|
export type InitStoreReturn<T> = {
|
|
19
19
|
get: () => T;
|
|
20
|
-
set: (value:
|
|
21
|
-
subscribe: (fn: (state: T) => void, selectDeps?: SelectDeps<T>
|
|
20
|
+
set: (value: SetStoreState<T>, silent?: boolean) => void;
|
|
21
|
+
subscribe: (fn: (state: T) => void, selectDeps?: SelectDeps<T>) => () => void;
|
|
22
22
|
getSubscribers: () => Subscribers<T>;
|
|
23
23
|
};
|
|
24
|
-
export declare const initStore: <T extends
|
|
24
|
+
export declare const initStore: <T extends StoreState>(initializer: StoreInitializer<T>, options?: InitStoreOptions<T>) => InitStoreReturn<T>;
|
|
@@ -1,55 +1,55 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.initStore = void 0;
|
|
4
|
-
const utils_1 = require("
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
5
|
const initStore = (initializer, options = {}) => {
|
|
6
6
|
const { intercept, onFirstSubscribe = utils_1.noop, onSubscribe = utils_1.noop, onUnsubscribe = utils_1.noop, onLastUnsubscribe = utils_1.noop, } = options;
|
|
7
7
|
const subscribers = new Map();
|
|
8
8
|
const getSubscribers = () => subscribers;
|
|
9
|
-
let
|
|
10
|
-
const get = () =>
|
|
9
|
+
let state;
|
|
10
|
+
const get = () => state;
|
|
11
11
|
const set = (value, silent = false) => {
|
|
12
|
-
const
|
|
13
|
-
|
|
12
|
+
const prevState = state;
|
|
13
|
+
state = { ...state, ...(0, utils_1.getValue)(value, state) };
|
|
14
14
|
if (intercept) {
|
|
15
|
-
|
|
15
|
+
state = { ...state, ...intercept(state, prevState) };
|
|
16
16
|
}
|
|
17
17
|
if (silent)
|
|
18
18
|
return;
|
|
19
|
-
const keys = Object.keys(
|
|
19
|
+
const keys = Object.keys(state);
|
|
20
20
|
subscribers.forEach((selectDeps, fn) => {
|
|
21
21
|
if (!selectDeps) {
|
|
22
22
|
for (let i = 0, n = keys.length; i < n; i++) {
|
|
23
|
-
if (
|
|
24
|
-
fn(
|
|
23
|
+
if (prevState[keys[i]] !== state[keys[i]]) {
|
|
24
|
+
fn(state);
|
|
25
25
|
break;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
|
-
const prevs = selectDeps(
|
|
31
|
-
const nexts = selectDeps(
|
|
30
|
+
const prevs = selectDeps(prevState);
|
|
31
|
+
const nexts = selectDeps(state);
|
|
32
32
|
for (let i = 0, n = prevs.length; i < n; i++) {
|
|
33
33
|
if (prevs[i] !== nexts[i]) {
|
|
34
|
-
fn(
|
|
34
|
+
fn(state);
|
|
35
35
|
break;
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
});
|
|
39
39
|
};
|
|
40
40
|
const subscribe = (fn, selectDeps) => {
|
|
41
|
-
subscribers.set(fn,
|
|
41
|
+
subscribers.set(fn, selectDeps);
|
|
42
42
|
if (subscribers.size === 1)
|
|
43
|
-
onFirstSubscribe(
|
|
44
|
-
onSubscribe(
|
|
43
|
+
onFirstSubscribe(state);
|
|
44
|
+
onSubscribe(state);
|
|
45
45
|
return () => {
|
|
46
46
|
subscribers.delete(fn);
|
|
47
|
-
onUnsubscribe(
|
|
47
|
+
onUnsubscribe(state);
|
|
48
48
|
if (subscribers.size === 0)
|
|
49
|
-
onLastUnsubscribe(
|
|
49
|
+
onLastUnsubscribe(state);
|
|
50
50
|
};
|
|
51
51
|
};
|
|
52
|
-
|
|
52
|
+
state = (0, utils_1.getValue)(initializer, { get, set });
|
|
53
53
|
return { get, set, subscribe, getSubscribers };
|
|
54
54
|
};
|
|
55
55
|
exports.initStore = initStore;
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|