async-fetch 0.2.6 → 0.2.7
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 +2 -5
- package/package.json +1 -1
- package/useAsyncFetch.js +41 -24
- package/useCache.js +33 -0
package/README.md
CHANGED
|
@@ -56,9 +56,10 @@ The minimum requirement for the hook is a url string as the first argument. The
|
|
|
56
56
|
| initialError | Any | Initial state for the error constant. | |
|
|
57
57
|
| deps | Array | List of dependencies to run the request on. | |
|
|
58
58
|
| poll | Number | Number of milliseconds to wait for polling requests. | |
|
|
59
|
+
| cachetime | Number | Number of milliseconds to cache responses for. | 60000 |
|
|
60
|
+
| timeout | Number | Number of milliseconds to wait before canceling the request. | 30000 |
|
|
59
61
|
| ignoreCleanup | Boolean | Whether or not the hook should cleanup on component unmount. | |
|
|
60
62
|
| ignoreRequest | Boolean | Whether or not the request should send. | |
|
|
61
|
-
| timeout | Number | Number of milliseconds to wait before canceling the request. | 30000 |
|
|
62
63
|
| query | Object | JSON object to append to the url as query params. | |
|
|
63
64
|
| params | Object | JSON object to append to the url as query params. | |
|
|
64
65
|
| data | Object | JSON object to send in the request body. | |
|
|
@@ -77,7 +78,3 @@ The minimum requirement for the hook is a url string as the first argument. The
|
|
|
77
78
|
| data | Any | The response data. |
|
|
78
79
|
| sendRequest | Function | Function to send the request manually. |
|
|
79
80
|
| cancelRequest | Function | Function to cancel the request manually. |
|
|
80
|
-
|
|
81
|
-
### Next.js
|
|
82
|
-
|
|
83
|
-
For the hook to work properly in a Next.js project you must turn `reactStrictMode` to false in your `next.config.js`.
|
package/package.json
CHANGED
package/useAsyncFetch.js
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { useState, useEffect } from "react";
|
|
2
|
+
import useCache from "./useCache.js";
|
|
2
3
|
import useInterval from "./useInterval.js";
|
|
3
4
|
|
|
4
|
-
function useAsyncFetch(
|
|
5
|
+
function useAsyncFetch(path, props = {}) {
|
|
5
6
|
const {
|
|
6
7
|
initialPending,
|
|
7
8
|
initialData,
|
|
8
9
|
initialError,
|
|
9
10
|
deps = [],
|
|
10
11
|
poll,
|
|
12
|
+
cachetime = 60000, // 1 minute.
|
|
13
|
+
timeout = 30000, // 5 minutes.
|
|
11
14
|
ignoreCleanup,
|
|
12
15
|
ignoreRequest,
|
|
13
|
-
timeout = 30000,
|
|
14
|
-
data: data2,
|
|
15
16
|
query,
|
|
16
17
|
params,
|
|
18
|
+
data: data2,
|
|
17
19
|
parser = "json",
|
|
18
20
|
onStart,
|
|
19
21
|
onSuccess,
|
|
@@ -34,13 +36,15 @@ function useAsyncFetch(url, props = {}) {
|
|
|
34
36
|
|
|
35
37
|
const [unmounted, setUnmounted] = useState(false);
|
|
36
38
|
|
|
39
|
+
const cache = useCache(cachetime);
|
|
40
|
+
|
|
37
41
|
useEffect(() => {
|
|
38
42
|
return cleanupRequest;
|
|
39
43
|
}, []);
|
|
40
44
|
|
|
41
45
|
useEffect(() => {
|
|
42
46
|
sendRequest();
|
|
43
|
-
}, [
|
|
47
|
+
}, [path, ...deps]);
|
|
44
48
|
|
|
45
49
|
useInterval(() => {
|
|
46
50
|
sendRequest();
|
|
@@ -58,9 +62,10 @@ function useAsyncFetch(url, props = {}) {
|
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
async function sendRequest() {
|
|
61
|
-
if (!
|
|
65
|
+
if (!path) throw new Error("URL is required.");
|
|
62
66
|
|
|
63
|
-
if (typeof
|
|
67
|
+
if (typeof path !== "string")
|
|
68
|
+
throw new Error("URL must be of type string.");
|
|
64
69
|
|
|
65
70
|
if (ignoreRequest !== true) {
|
|
66
71
|
const controller = new AbortController();
|
|
@@ -72,6 +77,13 @@ function useAsyncFetch(url, props = {}) {
|
|
|
72
77
|
}, timeout);
|
|
73
78
|
|
|
74
79
|
try {
|
|
80
|
+
let q = "";
|
|
81
|
+
|
|
82
|
+
if (query || params) {
|
|
83
|
+
if (!path.endsWith("?")) q += "?";
|
|
84
|
+
q += new URLSearchParams(query || params).toString();
|
|
85
|
+
}
|
|
86
|
+
|
|
75
87
|
const contentType =
|
|
76
88
|
fetchProps.headers?.["Content-Type"] ||
|
|
77
89
|
fetchProps.headers?.["content-type"];
|
|
@@ -82,36 +94,41 @@ function useAsyncFetch(url, props = {}) {
|
|
|
82
94
|
fetchProps.body = JSON.stringify(data2);
|
|
83
95
|
}
|
|
84
96
|
|
|
85
|
-
if (query || params) {
|
|
86
|
-
url += "?" + new URLSearchParams(query || params).toString();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
97
|
if (!unmounted) {
|
|
90
|
-
if (onStart) onStart();
|
|
91
98
|
if (pending) {
|
|
92
99
|
setPending2(true);
|
|
93
100
|
} else setPending(true);
|
|
94
101
|
setError();
|
|
95
102
|
cancelRequest();
|
|
96
103
|
setCancelSource(controller);
|
|
104
|
+
if (onStart) onStart();
|
|
97
105
|
}
|
|
98
106
|
|
|
99
|
-
const
|
|
107
|
+
const url = path + q;
|
|
108
|
+
|
|
109
|
+
const cachedResponse = cache.get(url, fetchProps);
|
|
110
|
+
|
|
111
|
+
let parsedResponse = cachedResponse;
|
|
100
112
|
|
|
101
|
-
if (!
|
|
102
|
-
|
|
103
|
-
JSON.stringify({
|
|
104
|
-
code: response.status,
|
|
105
|
-
text: response.statusText,
|
|
106
|
-
response: await response.text(),
|
|
107
|
-
})
|
|
108
|
-
);
|
|
113
|
+
if (!parsedResponse) {
|
|
114
|
+
const response = await fetch(url, fetchProps);
|
|
109
115
|
|
|
110
|
-
|
|
116
|
+
if (!response.ok)
|
|
117
|
+
throw new Error(
|
|
118
|
+
JSON.stringify({
|
|
119
|
+
code: response.status,
|
|
120
|
+
text: response.statusText,
|
|
121
|
+
response: await response.text(),
|
|
122
|
+
})
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
parsedResponse = await response[parser]();
|
|
126
|
+
}
|
|
111
127
|
|
|
112
128
|
if (!unmounted) {
|
|
113
|
-
if (onSuccess) onSuccess(parsedResponse);
|
|
114
129
|
setData(parsedResponse);
|
|
130
|
+
if (onSuccess) onSuccess(parsedResponse);
|
|
131
|
+
if (!cachedResponse) cache.set(url, fetchProps, parsedResponse);
|
|
115
132
|
}
|
|
116
133
|
} catch (e) {
|
|
117
134
|
if (!unmounted && e.name !== "AbortError") {
|
|
@@ -122,16 +139,16 @@ function useAsyncFetch(url, props = {}) {
|
|
|
122
139
|
} catch {
|
|
123
140
|
error = { response: e.toString(), text: e.toString() };
|
|
124
141
|
}
|
|
125
|
-
if (onFail) onFail(error);
|
|
126
142
|
setError(error);
|
|
143
|
+
if (onFail) onFail(error);
|
|
127
144
|
}
|
|
128
145
|
} finally {
|
|
129
146
|
clearTimeout(requestTimeout);
|
|
130
147
|
if (!unmounted) {
|
|
131
|
-
if (onFinish) onFinish();
|
|
132
148
|
if (pending) {
|
|
133
149
|
setPending2();
|
|
134
150
|
} else setPending();
|
|
151
|
+
if (onFinish) onFinish();
|
|
135
152
|
}
|
|
136
153
|
}
|
|
137
154
|
}
|
package/useCache.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import useInterval from "./useInterval.js";
|
|
2
|
+
|
|
3
|
+
const cache = {};
|
|
4
|
+
|
|
5
|
+
function useCache(cachetime) {
|
|
6
|
+
useInterval(() => {
|
|
7
|
+
for (let [key, value] of Object.entries(cache))
|
|
8
|
+
if (value.timestamp + cachetime < new Date().getTime()) delete cache[key];
|
|
9
|
+
}, cachetime);
|
|
10
|
+
|
|
11
|
+
function makeKey(url, fetchProps) {
|
|
12
|
+
return typeof fetchProps.body === "string" ? url + fetchProps.body : url;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function get(url, fetchProps) {
|
|
16
|
+
if (cachetime) {
|
|
17
|
+
const key = makeKey(url, fetchProps);
|
|
18
|
+
return cache[key]?.response;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function set(url, fetchProps, response) {
|
|
23
|
+
if (cachetime) {
|
|
24
|
+
const key = makeKey(url, fetchProps);
|
|
25
|
+
const payload = { timestamp: new Date().getTime(), response };
|
|
26
|
+
cache[key] = payload;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return { get, set };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default useCache;
|