async-fetch 0.2.1 → 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.
Files changed (3) hide show
  1. package/README.md +24 -19
  2. package/package.json +1 -1
  3. package/useAsyncFetch.js +90 -77
package/README.md CHANGED
@@ -10,15 +10,15 @@ $ npm i async-fetch
10
10
 
11
11
  ## Usage
12
12
 
13
- Provide your request config and handle the response.
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
- const App = () => {
19
+ function App() {
20
20
  const { pending, data, error, sendRequest, cancelRequest } = useAsyncFetch(
21
- "http://localhost:5000/api/v1/"
21
+ "https://jsonplaceholder.typicode.com/todos/1"
22
22
  );
23
23
 
24
24
  return (
@@ -40,34 +40,39 @@ const App = () => {
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 either a url string or an object with a url property. It is assumed that any other property that's provided is to be used for the actual fetch.
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 | Type | Definition | Default |
53
- | --------- | -------- | -------------------------------------------------------------------------------------------------------------- | ------- |
54
- | url | String | URL to send request to. | |
55
- | query | Object | Query parameters to include in the request (alt key name: "params"). | |
56
- | data | Object | Data object to include in the request body. | |
57
- | parser | String | Method used to parse the response. | "json" |
58
- | onStart | Function | Callback function to run before the request is sent. | |
59
- | onSuccess | Function | Callback function to run after the response has been parsed. The parsed response is available in the callback. | |
60
- | onFail | Function | Callback function to run when the request responds with an error. The error is available in the callback. | |
61
- | onFinish | Function | Callback function to run after the request has completed, regardless of success or failure. | |
62
- | deps | Array | Dependency array for the useEffect. | [] |
63
- | ignore | Boolean | Condition where if true the request won't send unless called using the sendRequest OUT property. | |
64
- | poll | Number | Time interval (in milliseconds) for polling. | |
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 or not. |
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "async-fetch",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Use fetch asynchronously for requests within React components.",
5
5
  "main": "useAsyncFetch.js",
6
6
  "scripts": {
package/useAsyncFetch.js CHANGED
@@ -1,78 +1,115 @@
1
1
  import { useState, useEffect } from "react";
2
2
  import useInterval from "./useInterval";
3
3
 
4
- let controller;
5
-
6
- function useAsyncFetch(props, props2) {
7
- let {
8
- url,
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: requestData,
16
+ data: data2,
12
17
  parser = "json",
13
18
  onStart,
14
19
  onSuccess,
15
20
  onFail,
16
21
  onFinish,
17
- deps = [],
18
- ignore,
19
- poll,
20
- ignoreCleanup,
21
- ...props3
22
- } = props instanceof Object ? props : {};
22
+ ...fetchProps
23
+ } = props;
23
24
 
24
- if (typeof props === "string") url = props;
25
+ const [pending, setPending] = useState(initialPending);
25
26
 
26
- const [pending1, setPending1] = useState();
27
+ const [data, setData] = useState(initialData);
27
28
 
28
- const [pending2, setPending2] = useState();
29
+ const [error, setError] = useState(initialError);
29
30
 
30
- const [error, setError] = useState();
31
+ const [cancelSource, setCancelSource] = useState();
31
32
 
32
- const [data, setData] = useState();
33
+ const [unmounted, setUnmounted] = useState(false);
33
34
 
34
- const [unmounted, setUnmounted] = useState();
35
+ useEffect(() => {
36
+ return cleanupRequest;
37
+ }, []);
35
38
 
36
- const cancelActiveRequest = () => controller?.abort?.();
39
+ useEffect(() => {
40
+ sendRequest();
41
+ }, [url, query, params, data2, ...deps]);
37
42
 
38
- async function sendRequest() {
39
- try {
40
- cancelActiveRequest();
43
+ useInterval(() => {
44
+ sendRequest();
45
+ }, poll);
41
46
 
42
- controller = new AbortController();
47
+ function cancelRequest(SOURCE) {
48
+ if (cancelSource?.abort) cancelSource.abort();
49
+ }
43
50
 
44
- if (!unmounted) {
45
- if (pending1) {
46
- setPending2(true);
47
- } else setPending1(true);
48
- setError();
49
- if (onStart) onStart();
50
- }
51
+ function cleanupRequest() {
52
+ if (ignoreCleanup !== true) {
53
+ setUnmounted(true);
54
+ cancelRequest();
55
+ }
56
+ }
51
57
 
52
- if (query || params)
53
- url += "?" + new URLSearchParams(query || params).toString();
58
+ async function sendRequest() {
59
+ if (!url) throw new Error("URL is required.");
54
60
 
55
- const response = await fetch(url, {
56
- signal: controller?.signal,
57
- body: requestData && JSON.stringify(requestData),
58
- ...props2,
59
- ...props3,
60
- });
61
+ if (typeof url !== "string") throw new Error("URL must be of type string.");
61
62
 
62
- if (!response.ok)
63
- throw new Error(
64
- JSON.stringify({
65
- code: response.status,
66
- text: response.statusText,
67
- response: await response.text(),
68
- })
69
- );
63
+ const controller = new AbortController();
70
64
 
71
- const parsedResponse = await response[parser]();
65
+ fetchProps.signal = controller.signal;
72
66
 
73
- if (!unmounted) {
74
- setData(parsedResponse);
75
- if (onSuccess) onSuccess(parsedResponse);
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
+ }
76
113
  }
77
114
  } catch (error) {
78
115
  if (!unmounted && error.name !== "AbortError") {
@@ -85,39 +122,15 @@ function useAsyncFetch(props, props2) {
85
122
  if (onFail) onFail(errorJson || error);
86
123
  }
87
124
  } finally {
125
+ clearTimeout(requestTimeout);
88
126
  if (!unmounted) {
89
- if (pending1) {
90
- setPending2(false);
91
- } else setPending1(false);
127
+ if (setPending) setPending();
92
128
  if (onFinish) onFinish();
93
129
  }
94
130
  }
95
131
  }
96
132
 
97
- useEffect(() => {
98
- if (ignore !== true) sendRequest();
99
- }, deps); // eslint-disable-line
100
-
101
- useInterval(() => {
102
- sendRequest();
103
- }, poll);
104
-
105
- useEffect(() => {
106
- if (!ignoreCleanup) {
107
- return () => {
108
- setUnmounted(true);
109
- cancelActiveRequest();
110
- };
111
- }
112
- }, []);
113
-
114
- return {
115
- pending: pending1 || pending2,
116
- error,
117
- data,
118
- sendRequest,
119
- cancelRequest: cancelActiveRequest,
120
- };
133
+ return { pending, data, error, sendRequest, cancelRequest };
121
134
  }
122
135
 
123
136
  export default useAsyncFetch;