async-fetch 0.2.0 → 0.2.2
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 +25 -20
- package/package.json +1 -1
- package/useAsyncFetch.js +90 -74
package/README.md
CHANGED
|
@@ -10,15 +10,15 @@ $ npm i async-fetch
|
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
|
-
Provide
|
|
13
|
+
Provide a url and handle the request.
|
|
14
14
|
|
|
15
15
|
```javascript
|
|
16
16
|
import React from "react";
|
|
17
17
|
import useAsyncFetch from "async-fetch";
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
function App() {
|
|
20
20
|
const { pending, data, error, sendRequest, cancelRequest } = useAsyncFetch(
|
|
21
|
-
"
|
|
21
|
+
"https://jsonplaceholder.typicode.com/todos/1"
|
|
22
22
|
);
|
|
23
23
|
|
|
24
24
|
return (
|
|
@@ -36,38 +36,43 @@ const App = () => {
|
|
|
36
36
|
: data
|
|
37
37
|
? JSON.stringify(data)
|
|
38
38
|
: error
|
|
39
|
-
?
|
|
39
|
+
? JSON.stringify(error)
|
|
40
40
|
: ""}
|
|
41
41
|
</React.Fragment>
|
|
42
42
|
);
|
|
43
|
-
}
|
|
43
|
+
}
|
|
44
44
|
|
|
45
45
|
export default App;
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
### Available IN Props And Definitions
|
|
49
49
|
|
|
50
|
-
The minimum requirement for the hook is
|
|
50
|
+
The minimum requirement for the hook is a url string as the first argument. The second argument has the following available options, while anything else that is provided is passed to the fetch request:
|
|
51
51
|
|
|
52
|
-
| Key
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
|
56
|
-
|
|
|
57
|
-
|
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
|
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
|
|
|
64
|
-
|
|
|
52
|
+
| Key | Type | Definition | Default |
|
|
53
|
+
| -------------- | -------- | --------------------------------------------------------------------------------------------------------------- | ------- |
|
|
54
|
+
| initialPending | Boolean | Initial state for the pending constant. | |
|
|
55
|
+
| initialData | Any | Initial state for the data constant. | |
|
|
56
|
+
| initialError | Any | Initial state for the error constant. | |
|
|
57
|
+
| deps | Array | List of dependencies to run the request on. | |
|
|
58
|
+
| poll | Number | Number of milliseconds to wait for polling requests. | |
|
|
59
|
+
| ignoreCleanup | Boolean | Whether or not the hook should cleanup on component unmount. | |
|
|
60
|
+
| ignoreRequest | Boolean | Whether or not the request should send. | |
|
|
61
|
+
| timeout | Number | Number of milliseconds to wait before canceling the request. | 30000 |
|
|
62
|
+
| query | Object | JSON object to append to the url as query params. | |
|
|
63
|
+
| params | Object | JSON object to append to the url as query params. | |
|
|
64
|
+
| data | Object | JSON object to send in the request body. | |
|
|
65
|
+
| parser | String | Method used to parse the response. | "json" |
|
|
66
|
+
| onStart | Function | Callback function to call when the request starts. | |
|
|
67
|
+
| onSuccess | Function | Callback function to call when the response has been received. The response is available as the first argument. | |
|
|
68
|
+
| onFail | Function | Callback function to call when the request has failed. The error is available as the first argument. | |
|
|
69
|
+
| onFinish | Function | Callback function to call when the request has finished. | |
|
|
65
70
|
|
|
66
71
|
### Available OUT Props And Definitions
|
|
67
72
|
|
|
68
73
|
| Key | Type | Definition |
|
|
69
74
|
| ------------- | -------- | ---------------------------------------- |
|
|
70
|
-
| pending | Boolean | Whether the request is active
|
|
75
|
+
| pending | Boolean | Whether or not the request is active. |
|
|
71
76
|
| error | Any | The response error. |
|
|
72
77
|
| data | Any | The response data. |
|
|
73
78
|
| sendRequest | Function | Function to send the request manually. |
|
package/package.json
CHANGED
package/useAsyncFetch.js
CHANGED
|
@@ -1,77 +1,115 @@
|
|
|
1
1
|
import { useState, useEffect } from "react";
|
|
2
2
|
import useInterval from "./useInterval";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
function useAsyncFetch(url, props = {}) {
|
|
5
|
+
const {
|
|
6
|
+
initialPending,
|
|
7
|
+
initialData,
|
|
8
|
+
initialError,
|
|
9
|
+
deps = [],
|
|
10
|
+
poll,
|
|
11
|
+
ignoreCleanup,
|
|
12
|
+
ignoreRequest,
|
|
13
|
+
timeout = 30000,
|
|
9
14
|
query,
|
|
10
15
|
params,
|
|
11
|
-
data:
|
|
16
|
+
data: data2,
|
|
12
17
|
parser = "json",
|
|
13
18
|
onStart,
|
|
14
19
|
onSuccess,
|
|
15
20
|
onFail,
|
|
16
21
|
onFinish,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
poll,
|
|
20
|
-
...props3
|
|
21
|
-
} = props instanceof Object ? props : {};
|
|
22
|
+
...fetchProps
|
|
23
|
+
} = props;
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
const [pending, setPending] = useState(initialPending);
|
|
24
26
|
|
|
25
|
-
const [
|
|
27
|
+
const [data, setData] = useState(initialData);
|
|
26
28
|
|
|
27
|
-
const [
|
|
29
|
+
const [error, setError] = useState(initialError);
|
|
28
30
|
|
|
29
|
-
const [
|
|
31
|
+
const [cancelSource, setCancelSource] = useState();
|
|
30
32
|
|
|
31
|
-
const [
|
|
33
|
+
const [unmounted, setUnmounted] = useState(false);
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
return cleanupRequest;
|
|
37
|
+
}, []);
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
sendRequest();
|
|
41
|
+
}, [url, query, params, data2, ...deps]);
|
|
36
42
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
useInterval(() => {
|
|
44
|
+
sendRequest();
|
|
45
|
+
}, poll);
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
function cancelRequest(SOURCE) {
|
|
48
|
+
if (cancelSource?.abort) cancelSource.abort();
|
|
49
|
+
}
|
|
42
50
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
51
|
+
function cleanupRequest() {
|
|
52
|
+
if (ignoreCleanup !== true) {
|
|
53
|
+
setUnmounted(true);
|
|
54
|
+
cancelRequest();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
50
57
|
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
async function sendRequest() {
|
|
59
|
+
if (!url) throw new Error("URL is required.");
|
|
53
60
|
|
|
54
|
-
|
|
55
|
-
signal: controller?.signal,
|
|
56
|
-
body: requestData && JSON.stringify(requestData),
|
|
57
|
-
...props2,
|
|
58
|
-
...props3,
|
|
59
|
-
});
|
|
61
|
+
if (typeof url !== "string") throw new Error("URL must be of type string.");
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
throw new Error(
|
|
63
|
-
JSON.stringify({
|
|
64
|
-
code: response.status,
|
|
65
|
-
text: response.statusText,
|
|
66
|
-
response: await response.text(),
|
|
67
|
-
})
|
|
68
|
-
);
|
|
63
|
+
const controller = new AbortController();
|
|
69
64
|
|
|
70
|
-
|
|
65
|
+
fetchProps.signal = controller.signal;
|
|
71
66
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
67
|
+
const requestTimeout = setTimeout(() => {
|
|
68
|
+
controller.abort();
|
|
69
|
+
}, timeout);
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
if (ignoreRequest !== true) {
|
|
73
|
+
const contentType =
|
|
74
|
+
fetchProps.headers?.["Content-Type"] ||
|
|
75
|
+
fetchProps.headers?.["content-type"];
|
|
76
|
+
|
|
77
|
+
if (contentType === "application/x-www-form-urlencoded") {
|
|
78
|
+
fetchProps.body = new URLSearchParams(data2 || {}).toString();
|
|
79
|
+
} else if (data2) {
|
|
80
|
+
fetchProps.body = JSON.stringify(data2);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (query || params) {
|
|
84
|
+
url += "?" + new URLSearchParams(query || params).toString();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!unmounted) {
|
|
88
|
+
if (onStart) onStart();
|
|
89
|
+
if (setPending) setPending(true);
|
|
90
|
+
if (setError) setError();
|
|
91
|
+
cancelRequest();
|
|
92
|
+
setCancelSource(controller);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const response = await fetch(url, fetchProps);
|
|
96
|
+
|
|
97
|
+
if (!response.ok)
|
|
98
|
+
throw new Error(
|
|
99
|
+
JSON.stringify({
|
|
100
|
+
code: response.status,
|
|
101
|
+
text: response.statusText,
|
|
102
|
+
response: await response.text(),
|
|
103
|
+
})
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const parsedResponse = await response[parser]();
|
|
107
|
+
|
|
108
|
+
if (!unmounted) {
|
|
109
|
+
setCancelSource();
|
|
110
|
+
setData(parsedResponse);
|
|
111
|
+
if (onSuccess) onSuccess(parsedResponse);
|
|
112
|
+
}
|
|
75
113
|
}
|
|
76
114
|
} catch (error) {
|
|
77
115
|
if (!unmounted && error.name !== "AbortError") {
|
|
@@ -84,37 +122,15 @@ function useAsyncFetch(props, props2) {
|
|
|
84
122
|
if (onFail) onFail(errorJson || error);
|
|
85
123
|
}
|
|
86
124
|
} finally {
|
|
125
|
+
clearTimeout(requestTimeout);
|
|
87
126
|
if (!unmounted) {
|
|
88
|
-
if (
|
|
89
|
-
setPending2(false);
|
|
90
|
-
} else setPending1(false);
|
|
127
|
+
if (setPending) setPending();
|
|
91
128
|
if (onFinish) onFinish();
|
|
92
129
|
}
|
|
93
130
|
}
|
|
94
131
|
}
|
|
95
132
|
|
|
96
|
-
|
|
97
|
-
if (ignore !== true) sendRequest();
|
|
98
|
-
}, deps); // eslint-disable-line
|
|
99
|
-
|
|
100
|
-
useInterval(() => {
|
|
101
|
-
sendRequest();
|
|
102
|
-
}, poll);
|
|
103
|
-
|
|
104
|
-
useEffect(() => {
|
|
105
|
-
return () => {
|
|
106
|
-
setUnmounted(true);
|
|
107
|
-
cancelActiveRequest();
|
|
108
|
-
};
|
|
109
|
-
}, []);
|
|
110
|
-
|
|
111
|
-
return {
|
|
112
|
-
pending: pending1 || pending2,
|
|
113
|
-
error,
|
|
114
|
-
data,
|
|
115
|
-
sendRequest,
|
|
116
|
-
cancelRequest: cancelActiveRequest,
|
|
117
|
-
};
|
|
133
|
+
return { pending, data, error, sendRequest, cancelRequest };
|
|
118
134
|
}
|
|
119
135
|
|
|
120
136
|
export default useAsyncFetch;
|