async-fetch 0.2.4 → 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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "async-fetch",
3
- "version": "0.2.4",
3
+ "version": "0.2.7",
4
4
  "description": "Use fetch asynchronously for requests within React components.",
5
5
  "main": "useAsyncFetch.js",
6
6
  "type": "module",
package/useAsyncFetch.js CHANGED
@@ -1,16 +1,18 @@
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(url, props = {}) {
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
16
  query,
15
17
  params,
16
18
  data: data2,
@@ -24,6 +26,8 @@ function useAsyncFetch(url, props = {}) {
24
26
 
25
27
  const [pending, setPending] = useState(initialPending);
26
28
 
29
+ const [pending2, setPending2] = useState();
30
+
27
31
  const [data, setData] = useState(initialData);
28
32
 
29
33
  const [error, setError] = useState(initialError);
@@ -32,19 +36,21 @@ function useAsyncFetch(url, props = {}) {
32
36
 
33
37
  const [unmounted, setUnmounted] = useState(false);
34
38
 
39
+ const cache = useCache(cachetime);
40
+
35
41
  useEffect(() => {
36
42
  return cleanupRequest;
37
43
  }, []);
38
44
 
39
45
  useEffect(() => {
40
46
  sendRequest();
41
- }, [url, query, params, data2, ...deps]);
47
+ }, [path, ...deps]);
42
48
 
43
49
  useInterval(() => {
44
50
  sendRequest();
45
51
  }, poll);
46
52
 
47
- function cancelRequest(SOURCE) {
53
+ function cancelRequest() {
48
54
  if (cancelSource?.abort) cancelSource.abort();
49
55
  }
50
56
 
@@ -56,20 +62,28 @@ function useAsyncFetch(url, props = {}) {
56
62
  }
57
63
 
58
64
  async function sendRequest() {
59
- if (!url) throw new Error("URL is required.");
65
+ if (!path) throw new Error("URL is required.");
66
+
67
+ if (typeof path !== "string")
68
+ throw new Error("URL must be of type string.");
60
69
 
61
- if (typeof url !== "string") throw new Error("URL must be of type string.");
70
+ if (ignoreRequest !== true) {
71
+ const controller = new AbortController();
62
72
 
63
- const controller = new AbortController();
73
+ fetchProps.signal = controller.signal;
64
74
 
65
- fetchProps.signal = controller.signal;
75
+ const requestTimeout = setTimeout(() => {
76
+ controller.abort();
77
+ }, timeout);
66
78
 
67
- const requestTimeout = setTimeout(() => {
68
- controller.abort();
69
- }, timeout);
79
+ try {
80
+ let q = "";
81
+
82
+ if (query || params) {
83
+ if (!path.endsWith("?")) q += "?";
84
+ q += new URLSearchParams(query || params).toString();
85
+ }
70
86
 
71
- try {
72
- if (ignoreRequest !== true) {
73
87
  const contentType =
74
88
  fetchProps.headers?.["Content-Type"] ||
75
89
  fetchProps.headers?.["content-type"];
@@ -80,57 +94,73 @@ function useAsyncFetch(url, props = {}) {
80
94
  fetchProps.body = JSON.stringify(data2);
81
95
  }
82
96
 
83
- if (query || params) {
84
- url += "?" + new URLSearchParams(query || params).toString();
85
- }
86
-
87
97
  if (!unmounted) {
88
- if (onStart) onStart();
89
- if (setPending) setPending(true);
90
- if (setError) setError();
98
+ if (pending) {
99
+ setPending2(true);
100
+ } else setPending(true);
101
+ setError();
91
102
  cancelRequest();
92
103
  setCancelSource(controller);
104
+ if (onStart) onStart();
93
105
  }
94
106
 
95
- const response = await fetch(url, fetchProps);
107
+ const url = path + q;
108
+
109
+ const cachedResponse = cache.get(url, fetchProps);
110
+
111
+ let parsedResponse = cachedResponse;
96
112
 
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
- );
113
+ if (!parsedResponse) {
114
+ const response = await fetch(url, fetchProps);
105
115
 
106
- const parsedResponse = await response[parser]();
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
+ }
107
127
 
108
128
  if (!unmounted) {
109
- setCancelSource();
110
129
  setData(parsedResponse);
111
130
  if (onSuccess) onSuccess(parsedResponse);
131
+ if (!cachedResponse) cache.set(url, fetchProps, parsedResponse);
132
+ }
133
+ } catch (e) {
134
+ if (!unmounted && e.name !== "AbortError") {
135
+ let error;
136
+ try {
137
+ error = e.toString().replace("Error:", "");
138
+ error = JSON.parse(error.trim());
139
+ } catch {
140
+ error = { response: e.toString(), text: e.toString() };
141
+ }
142
+ setError(error);
143
+ if (onFail) onFail(error);
144
+ }
145
+ } finally {
146
+ clearTimeout(requestTimeout);
147
+ if (!unmounted) {
148
+ if (pending) {
149
+ setPending2();
150
+ } else setPending();
151
+ if (onFinish) onFinish();
112
152
  }
113
- }
114
- } catch (error) {
115
- if (!unmounted && error.name !== "AbortError") {
116
- let errorJson;
117
- try {
118
- errorJson = error.toString().replace("Error:", "");
119
- errorJson = JSON.parse(errorJson.trim());
120
- } catch {}
121
- setError(errorJson || error);
122
- if (onFail) onFail(errorJson || error);
123
- }
124
- } finally {
125
- clearTimeout(requestTimeout);
126
- if (!unmounted) {
127
- if (setPending) setPending();
128
- if (onFinish) onFinish();
129
153
  }
130
154
  }
131
155
  }
132
156
 
133
- return { pending, data, error, sendRequest, cancelRequest };
157
+ return {
158
+ pending: pending || pending2,
159
+ data,
160
+ error,
161
+ sendRequest,
162
+ cancelRequest,
163
+ };
134
164
  }
135
165
 
136
166
  export default useAsyncFetch;
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;