@kirill.konshin/react 0.0.1 → 0.0.3
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/.ctirc +19 -10
- package/.turbo/turbo-build.log +13 -32
- package/CHANGELOG.md +14 -0
- package/README.md +56 -0
- package/dist/form/form.d.ts +10 -10
- package/dist/form/form.d.ts.map +1 -1
- package/dist/form/form.js +6 -6
- package/dist/form/form.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/keyboard.d.ts +4 -1
- package/dist/keyboard.d.ts.map +1 -1
- package/dist/keyboard.js +3 -3
- package/dist/keyboard.js.map +1 -1
- package/dist/useFetch.d.ts +28 -1
- package/dist/useFetch.d.ts.map +1 -1
- package/dist/useFetch.js +51 -5
- package/dist/useFetch.js.map +1 -1
- package/dist/useFetch.test.d.ts +2 -0
- package/dist/useFetch.test.d.ts.map +1 -0
- package/package.json +17 -5
- package/src/form/form.tsx +22 -22
- package/src/index.ts +1 -1
- package/src/keyboard.tsx +18 -3
- package/src/useFetch.test.tsx +424 -0
- package/src/useFetch.ts +91 -11
package/src/useFetch.ts
CHANGED
|
@@ -1,29 +1,109 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useCallback, useState, useTransition } from 'react';
|
|
3
|
+
import { useCallback, useEffect, useRef, useState, useTransition } from 'react';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const unmountError = 'Component is unmounted after fetch completed';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* TODO useFetch https://use-http.com
|
|
9
|
+
* TODO SWR?
|
|
10
|
+
* TODO Tanstack Query?
|
|
11
|
+
*
|
|
12
|
+
* Uses same return array patterns as useActionState https://react.dev/reference/react/useActionState + error,
|
|
13
|
+
* reason: simple var rename
|
|
14
|
+
*
|
|
15
|
+
* Function can be async, then it will be awaited and result set to state.
|
|
16
|
+
*
|
|
17
|
+
* Function can be sync, then it will be called args, and it should return another function,which will be called with
|
|
18
|
+
* old data and result set to state. This is useful for pagination and merging data.
|
|
19
|
+
*
|
|
20
|
+
* @param {(...args: any[]) => Promise<R> | R | ((oldData: R) => Promise<R> | R))} fn
|
|
21
|
+
* @param {any} defaultValue
|
|
22
|
+
* @param fetchOnMount
|
|
23
|
+
* @param throwAfterUnmount - throw if component is unmounted after fetch completed
|
|
24
|
+
* @returns {[R, (...args: any[]) => Promise<R>, boolean, Error | undefined]} //, ReturnType<typeof useState>, ReturnType<typeof useState>
|
|
25
|
+
*/
|
|
8
26
|
export function useFetch<R>(
|
|
9
|
-
fn: (...args: any[]) => Promise<R
|
|
10
|
-
defaultValue: R
|
|
11
|
-
|
|
27
|
+
fn: (...args: any[]) => Promise<R> | R | ((oldData: R) => Promise<R> | R),
|
|
28
|
+
defaultValue: R,
|
|
29
|
+
{
|
|
30
|
+
fetchOnMount = false,
|
|
31
|
+
throwAfterUnmount = false,
|
|
32
|
+
}: {
|
|
33
|
+
fetchOnMount?: boolean;
|
|
34
|
+
throwAfterUnmount?: boolean;
|
|
35
|
+
} = {},
|
|
36
|
+
): [
|
|
37
|
+
R,
|
|
38
|
+
(...args: Parameters<typeof fn>) => Promise<R>,
|
|
39
|
+
boolean,
|
|
40
|
+
Error | undefined,
|
|
41
|
+
// ReturnType<typeof useState<R>>[1],
|
|
42
|
+
// ReturnType<typeof useState<Error>>[1],
|
|
43
|
+
] {
|
|
12
44
|
// An async function was passed to useActionState, but it was dispatched outside of an action context.
|
|
13
45
|
// This is likely not what you intended. Either pass the dispatch function to an `action` prop, or dispatch manually inside `startTransition`
|
|
14
46
|
const [isPending, startTransition] = useTransition();
|
|
15
|
-
const [data, setData] = useState<R
|
|
47
|
+
const [data, setData] = useState<R>(defaultValue);
|
|
16
48
|
const [error, setError] = useState<Error>();
|
|
49
|
+
const [loading, setLoading] = useState(fetchOnMount);
|
|
50
|
+
const isMounted = useRef(false);
|
|
51
|
+
const oldData = useRef(data);
|
|
52
|
+
const throwAfterUnmountRef = useRef(throwAfterUnmount);
|
|
17
53
|
|
|
18
54
|
const actionFn = useCallback(
|
|
19
55
|
(...args: Parameters<typeof fn>) => {
|
|
20
|
-
const
|
|
56
|
+
const res = fn(...args);
|
|
57
|
+
|
|
58
|
+
const promise: Promise<R> = typeof res === 'function' ? (res as any)(oldData.current) : (res as Promise<R>);
|
|
59
|
+
|
|
21
60
|
// https://react.dev/reference/react/useTransition#react-doesnt-treat-my-state-update-after-await-as-a-transition
|
|
22
|
-
startTransition(() =>
|
|
61
|
+
startTransition(async () => {
|
|
62
|
+
try {
|
|
63
|
+
const newData = await promise;
|
|
64
|
+
if (!isMounted.current) {
|
|
65
|
+
if (throwAfterUnmountRef.current) throw new Error(unmountError);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
oldData.current = newData;
|
|
69
|
+
setData(newData);
|
|
70
|
+
setError(undefined);
|
|
71
|
+
} catch (e) {
|
|
72
|
+
if (!isMounted.current) {
|
|
73
|
+
if (throwAfterUnmountRef.current) {
|
|
74
|
+
if (e.message !== unmountError) throw new Error('Component is unmounted', { cause: e });
|
|
75
|
+
else throw e;
|
|
76
|
+
}
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
setError(e);
|
|
80
|
+
} finally {
|
|
81
|
+
if (isMounted.current) {
|
|
82
|
+
setLoading(false);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
23
87
|
return promise;
|
|
24
88
|
},
|
|
25
89
|
[fn],
|
|
26
90
|
);
|
|
27
91
|
|
|
28
|
-
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (!fetchOnMount) return;
|
|
94
|
+
actionFn().catch((e) => console.error('Fetch on mount failed', e)); // catch actually will never happen
|
|
95
|
+
}, [fetchOnMount, fn, actionFn]);
|
|
96
|
+
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
throwAfterUnmountRef.current = throwAfterUnmount;
|
|
99
|
+
}, [throwAfterUnmount]);
|
|
100
|
+
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
isMounted.current = true;
|
|
103
|
+
return () => {
|
|
104
|
+
isMounted.current = false;
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return [data, actionFn, isPending || loading, error]; // , setData, setError
|
|
29
109
|
}
|