async-fetch 0.3.7 → 0.3.8
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 +9 -9
- package/dist/index.d.ts +2 -29
- package/dist/index.js +65 -72
- package/dist/interfaces.d.ts +30 -0
- package/dist/interfaces.js +1 -0
- package/dist/normalizeError.d.ts +3 -0
- package/dist/normalizeError.js +22 -0
- package/dist/useInterval.js +7 -7
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -51,18 +51,18 @@ The minimum requirement for the hook is a url string as the first argument. The
|
|
|
51
51
|
|
|
52
52
|
| Key | Type | Definition | Default |
|
|
53
53
|
| -------------- | -------- | --------------------------------------------------------------------------------------------------------------- | ------- |
|
|
54
|
-
| initialPending | Boolean | Initial state for the pending constant. |
|
|
55
|
-
|
|
|
56
|
-
|
|
|
57
|
-
|
|
|
54
|
+
| initialPending | Boolean | Initial state for the pending constant. | false |
|
|
55
|
+
| initialError | E or Any | Initial state for the error constant. | |
|
|
56
|
+
| initialData | T or Any | Initial state for the data constant. | |
|
|
57
|
+
| auto | Boolean | Whether or not the request should send on mount. | true |
|
|
58
58
|
| poll | Number | Number of milliseconds to wait for polling requests. | |
|
|
59
59
|
| timeout | Number | Number of milliseconds to wait before canceling the request. | 30000 |
|
|
60
|
-
| ignoreCleanup | Boolean | Whether or not the hook should cleanup on component unmount. | |
|
|
61
60
|
| ignoreRequest | Boolean | Whether or not the request should send. | |
|
|
61
|
+
| ignoreCleanup | Boolean | Whether or not the hook should cleanup on component unmount. | |
|
|
62
62
|
| query | Object | JSON object to append to the url as search params. | |
|
|
63
63
|
| params | Object | JSON object to append to the url as search params. | |
|
|
64
|
-
| data |
|
|
65
|
-
| parser | String | Method used to parse the response.
|
|
64
|
+
| data | Any | JSON object to send in the request body. | |
|
|
65
|
+
| parser | String | Method used to parse the response. Options: json, text, blob, formData, arrayBuffer. | "json" |
|
|
66
66
|
| onStart | Function | Callback function to call when the request starts. | |
|
|
67
67
|
| onSuccess | Function | Callback function to call when the response has been received. The response is available as the first argument. | |
|
|
68
68
|
| onFail | Function | Callback function to call when the request has failed. The error is available as the first argument. | |
|
|
@@ -73,7 +73,7 @@ The minimum requirement for the hook is a url string as the first argument. The
|
|
|
73
73
|
| Key | Type | Definition |
|
|
74
74
|
| ------------- | -------- | ---------------------------------------- |
|
|
75
75
|
| pending | Boolean | Whether or not the request is active. |
|
|
76
|
-
| error | Any
|
|
77
|
-
| data | Any
|
|
76
|
+
| error | E or Any | The response error. |
|
|
77
|
+
| data | T or Any | The response data. |
|
|
78
78
|
| sendRequest | Function | Function to send the request manually. |
|
|
79
79
|
| cancelRequest | Function | Function to cancel the request manually. |
|
package/dist/index.d.ts
CHANGED
|
@@ -1,30 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
initialData?: any;
|
|
4
|
-
initialError?: any;
|
|
5
|
-
deps?: string[];
|
|
6
|
-
poll?: number;
|
|
7
|
-
timeout?: number;
|
|
8
|
-
ignoreRequest?: boolean;
|
|
9
|
-
ignoreCleanup?: boolean;
|
|
10
|
-
query?: any;
|
|
11
|
-
params?: any;
|
|
12
|
-
data?: any;
|
|
13
|
-
parser?: "json" | "text" | "blob" | "formData" | "arrayBuffer";
|
|
14
|
-
onStart?: () => void;
|
|
15
|
-
onSuccess?: (data: any) => void;
|
|
16
|
-
onFail?: (error: any) => void;
|
|
17
|
-
onFinish?: () => void;
|
|
18
|
-
headers?: Record<string, string>;
|
|
19
|
-
body?: any;
|
|
20
|
-
signal?: AbortSignal;
|
|
21
|
-
}
|
|
22
|
-
interface ResponseProps {
|
|
23
|
-
pending?: boolean;
|
|
24
|
-
data?: any;
|
|
25
|
-
error?: any;
|
|
26
|
-
sendRequest: () => void;
|
|
27
|
-
cancelRequest: () => void;
|
|
28
|
-
}
|
|
29
|
-
declare function useAsyncFetch(stringUrl: string, props?: RequestProps): ResponseProps;
|
|
1
|
+
import { FetchError, RequestProps, ResponseProps } from "./interfaces";
|
|
2
|
+
declare function useAsyncFetch<T = any, E = FetchError>(urlString: string, props?: RequestProps<T, E>): ResponseProps<T, E>;
|
|
30
3
|
export default useAsyncFetch;
|
package/dist/index.js
CHANGED
|
@@ -1,93 +1,85 @@
|
|
|
1
|
-
import { useState, useCallback, useEffect } from "react";
|
|
1
|
+
import { useState, useRef, useCallback, useEffect } from "react";
|
|
2
2
|
import useInterval from "./useInterval.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
ignoreRequest, ignoreCleanup, query, params, data: body, parser = "json", onStart, onSuccess, onFail, onFinish, ...
|
|
3
|
+
import normalizeError from "./normalizeError.js";
|
|
4
|
+
function useAsyncFetch(urlString, props = {}) {
|
|
5
|
+
const { initialPending = false, initialError, initialData, auto = true, poll, timeout = 30000, ignoreRequest, ignoreCleanup, query, params, data: body, parser = "json", onStart, onSuccess, onFail, onFinish, ...fetchOptions } = props;
|
|
6
6
|
const [pending, setPending] = useState(initialPending);
|
|
7
|
-
const [pending2, setPending2] = useState(initialPending);
|
|
8
|
-
const [data, setData] = useState(initialData);
|
|
9
7
|
const [error, setError] = useState(initialError);
|
|
10
|
-
const [
|
|
8
|
+
const [data, setData] = useState(initialData);
|
|
9
|
+
const fetchOptionsRef = useRef(fetchOptions);
|
|
10
|
+
const controllerRef = useRef(null);
|
|
11
|
+
const requestIdRef = useRef(0);
|
|
12
|
+
fetchOptionsRef.current = fetchOptions;
|
|
11
13
|
const cancelRequest = useCallback(() => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}, [
|
|
14
|
+
controllerRef.current?.abort();
|
|
15
|
+
controllerRef.current = null;
|
|
16
|
+
}, []);
|
|
15
17
|
const sendRequest = useCallback(async () => {
|
|
16
18
|
if (ignoreRequest === true)
|
|
17
19
|
return;
|
|
18
|
-
const url = new URL(stringUrl, window.location.origin);
|
|
19
|
-
if (query || params) {
|
|
20
|
-
url.search = new URLSearchParams(query || params || {}).toString();
|
|
21
|
-
}
|
|
22
|
-
const contentType = fetchProps.headers?.["Content-Type"] ||
|
|
23
|
-
fetchProps.headers?.["content-type"];
|
|
24
|
-
if (contentType === "application/x-www-form-urlencoded") {
|
|
25
|
-
fetchProps.body = new URLSearchParams(body || {});
|
|
26
|
-
}
|
|
27
|
-
else if (body) {
|
|
28
|
-
fetchProps.body = JSON.stringify(body);
|
|
29
|
-
}
|
|
30
|
-
const controller = new AbortController();
|
|
31
|
-
const requestTimeout = setTimeout(() => controller.abort(), timeout);
|
|
32
|
-
fetchProps.signal = controller.signal;
|
|
33
|
-
if (pending)
|
|
34
|
-
setPending2(true);
|
|
35
|
-
if (!pending)
|
|
36
|
-
setPending(true);
|
|
37
|
-
setError(undefined);
|
|
38
20
|
cancelRequest();
|
|
39
|
-
|
|
21
|
+
setPending(true);
|
|
22
|
+
setError(undefined);
|
|
40
23
|
if (onStart)
|
|
41
24
|
onStart();
|
|
25
|
+
const controller = new AbortController();
|
|
26
|
+
controllerRef.current = controller;
|
|
27
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
28
|
+
const requestId = ++requestIdRef.current;
|
|
42
29
|
try {
|
|
43
|
-
const
|
|
30
|
+
const url = new URL(urlString, window.location.origin);
|
|
31
|
+
url.search = new URLSearchParams({ ...query, ...params }).toString();
|
|
32
|
+
const headers = new Headers(fetchOptionsRef.current.headers);
|
|
33
|
+
let resolvedBody;
|
|
34
|
+
if (headers.get("content-type") === "application/x-www-form-urlencoded") {
|
|
35
|
+
resolvedBody = new URLSearchParams(body ?? {});
|
|
36
|
+
}
|
|
37
|
+
else if (body instanceof FormData || body instanceof Blob) {
|
|
38
|
+
resolvedBody = body;
|
|
39
|
+
}
|
|
40
|
+
else if (body !== undefined) {
|
|
41
|
+
resolvedBody = JSON.stringify(body);
|
|
42
|
+
}
|
|
43
|
+
const response = await fetch(url, {
|
|
44
|
+
...fetchOptionsRef.current,
|
|
45
|
+
headers,
|
|
46
|
+
body: resolvedBody ?? fetchOptionsRef.current.body,
|
|
47
|
+
signal: controller.signal,
|
|
48
|
+
});
|
|
44
49
|
if (!response.ok) {
|
|
45
|
-
throw
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
throw {
|
|
51
|
+
status: response.status,
|
|
52
|
+
statusText: response.statusText,
|
|
48
53
|
response: await response.text(),
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
const parsedResponse = await response[parser]();
|
|
53
|
-
setData(parsedResponse);
|
|
54
|
-
if (onSuccess)
|
|
55
|
-
onSuccess(parsedResponse);
|
|
54
|
+
};
|
|
56
55
|
}
|
|
56
|
+
const parsedResponse = (await response[parser]());
|
|
57
|
+
setData(parsedResponse);
|
|
58
|
+
onSuccess?.(parsedResponse);
|
|
57
59
|
}
|
|
58
|
-
catch (
|
|
59
|
-
if (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
catch {
|
|
65
|
-
error = { response: e.toString(), text: e.toString() };
|
|
66
|
-
}
|
|
67
|
-
setError(error);
|
|
68
|
-
if (onFail)
|
|
69
|
-
onFail(error);
|
|
70
|
-
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
if (err?.name === "AbortError")
|
|
62
|
+
return;
|
|
63
|
+
const normalized = normalizeError(err);
|
|
64
|
+
setError(normalized);
|
|
65
|
+
onFail?.(normalized);
|
|
71
66
|
}
|
|
72
67
|
finally {
|
|
73
|
-
clearTimeout(
|
|
74
|
-
if (
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
setPending(undefined);
|
|
68
|
+
clearTimeout(timeoutId);
|
|
69
|
+
if (requestId === requestIdRef.current) {
|
|
70
|
+
setPending(false);
|
|
71
|
+
if (onFinish)
|
|
72
|
+
onFinish();
|
|
79
73
|
}
|
|
80
|
-
if (onFinish)
|
|
81
|
-
onFinish();
|
|
82
74
|
}
|
|
83
75
|
}, [
|
|
84
76
|
ignoreRequest,
|
|
85
|
-
|
|
77
|
+
cancelRequest,
|
|
78
|
+
timeout,
|
|
79
|
+
urlString,
|
|
86
80
|
query,
|
|
87
81
|
params,
|
|
88
|
-
fetchProps,
|
|
89
82
|
body,
|
|
90
|
-
timeout,
|
|
91
83
|
parser,
|
|
92
84
|
onStart,
|
|
93
85
|
onSuccess,
|
|
@@ -95,8 +87,9 @@ function useAsyncFetch(stringUrl, props = {}) {
|
|
|
95
87
|
onFinish,
|
|
96
88
|
]);
|
|
97
89
|
useEffect(() => {
|
|
98
|
-
|
|
99
|
-
|
|
90
|
+
if (auto)
|
|
91
|
+
sendRequest();
|
|
92
|
+
}, [auto, sendRequest]);
|
|
100
93
|
useInterval(() => {
|
|
101
94
|
sendRequest();
|
|
102
95
|
}, poll);
|
|
@@ -105,13 +98,13 @@ function useAsyncFetch(stringUrl, props = {}) {
|
|
|
105
98
|
if (ignoreCleanup !== true)
|
|
106
99
|
cancelRequest();
|
|
107
100
|
};
|
|
108
|
-
}, []);
|
|
101
|
+
}, [ignoreCleanup, cancelRequest]);
|
|
109
102
|
return {
|
|
110
|
-
pending
|
|
111
|
-
data,
|
|
103
|
+
pending,
|
|
112
104
|
error,
|
|
113
|
-
|
|
105
|
+
data,
|
|
114
106
|
cancelRequest,
|
|
107
|
+
sendRequest,
|
|
115
108
|
};
|
|
116
109
|
}
|
|
117
110
|
export default useAsyncFetch;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface FetchError {
|
|
2
|
+
status: number;
|
|
3
|
+
statusText: string;
|
|
4
|
+
response: string;
|
|
5
|
+
}
|
|
6
|
+
export interface RequestProps<T, E> extends RequestInit {
|
|
7
|
+
initialPending?: boolean;
|
|
8
|
+
initialError?: E;
|
|
9
|
+
initialData?: T;
|
|
10
|
+
auto?: boolean;
|
|
11
|
+
poll?: number;
|
|
12
|
+
timeout?: number;
|
|
13
|
+
ignoreRequest?: boolean;
|
|
14
|
+
ignoreCleanup?: boolean;
|
|
15
|
+
query?: Record<string, any>;
|
|
16
|
+
params?: Record<string, any>;
|
|
17
|
+
data?: any;
|
|
18
|
+
parser?: "json" | "text" | "blob" | "formData" | "arrayBuffer";
|
|
19
|
+
onStart?: () => void;
|
|
20
|
+
onSuccess?: (data: T) => void;
|
|
21
|
+
onFail?: (error: E) => void;
|
|
22
|
+
onFinish?: () => void;
|
|
23
|
+
}
|
|
24
|
+
export interface ResponseProps<T, E> {
|
|
25
|
+
pending: boolean;
|
|
26
|
+
error?: E;
|
|
27
|
+
data?: T;
|
|
28
|
+
sendRequest: () => Promise<void>;
|
|
29
|
+
cancelRequest: () => void;
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
function normalizeError(err) {
|
|
2
|
+
if (err instanceof Error) {
|
|
3
|
+
return {
|
|
4
|
+
status: 500,
|
|
5
|
+
statusText: err.message,
|
|
6
|
+
response: err.stack ?? "",
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
if (typeof err === "object" && err !== null) {
|
|
10
|
+
return {
|
|
11
|
+
status: err.status ?? 500,
|
|
12
|
+
statusText: err.statusText ?? "",
|
|
13
|
+
response: err.response ?? "",
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
status: 500,
|
|
18
|
+
statusText: String(err),
|
|
19
|
+
response: "",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export default normalizeError;
|
package/dist/useInterval.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { useRef, useEffect } from "react";
|
|
2
2
|
function useInterval(callback, poll) {
|
|
3
|
-
const callbackRef = useRef(() => { });
|
|
3
|
+
const callbackRef = useRef(() => { });
|
|
4
4
|
useEffect(() => {
|
|
5
|
-
|
|
6
|
-
callbackRef.current = callback;
|
|
7
|
-
}
|
|
5
|
+
callbackRef.current = callback;
|
|
8
6
|
}, [callback]);
|
|
9
7
|
useEffect(() => {
|
|
10
|
-
if (
|
|
8
|
+
if (!Number.isInteger(poll))
|
|
11
9
|
return;
|
|
12
|
-
const
|
|
13
|
-
|
|
10
|
+
const id = setInterval(() => {
|
|
11
|
+
callbackRef.current?.();
|
|
12
|
+
}, poll);
|
|
13
|
+
return () => clearInterval(id);
|
|
14
14
|
}, [poll]);
|
|
15
15
|
}
|
|
16
16
|
export default useInterval;
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "async-fetch",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"description": "Use async fetch hook for requests within React components.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"build": "tsc",
|
|
9
|
+
"build": "npx rimraf dist && tsc",
|
|
10
10
|
"test-esm": "yarn build && node test/test-esm.mjs"
|
|
11
11
|
},
|
|
12
12
|
"repository": {
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
},
|
|
27
27
|
"homepage": "https://github.com/nameer-rizvi/useAsyncFetch#readme",
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@types/node": "^
|
|
30
|
-
"@types/react": "^
|
|
31
|
-
"react": "^
|
|
29
|
+
"@types/node": "^25.0.3",
|
|
30
|
+
"@types/react": "^19.2.7",
|
|
31
|
+
"react": "^19.2.3",
|
|
32
32
|
"ts-node": "^10.9.2",
|
|
33
|
-
"typescript": "^5.
|
|
33
|
+
"typescript": "^5.9.3"
|
|
34
34
|
}
|
|
35
35
|
}
|