use-abort 1.0.0 → 1.0.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 +102 -23
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# use-abort
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React hook for auto-canceling async API calls with AbortController. Prevents race conditions, handles cleanup, and works with fetch/axios.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ A lightweight, production-ready React hook for safely handling async API calls w
|
|
|
10
10
|
✅ **Error Handling** - Gracefully handles errors while ignoring abort errors
|
|
11
11
|
✅ **TypeScript First** - Full type safety with TypeScript generics
|
|
12
12
|
✅ **Zero Dependencies** - Only requires React (peer dependency)
|
|
13
|
-
✅ **Framework Agnostic** - Works with
|
|
13
|
+
✅ **Framework Agnostic** - Works with fetch, axios, or any async function
|
|
14
14
|
|
|
15
15
|
## Installation
|
|
16
16
|
|
|
@@ -18,43 +18,122 @@ A lightweight, production-ready React hook for safely handling async API calls w
|
|
|
18
18
|
npm install use-abort
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { useAbort } from "use-abort";
|
|
25
|
+
|
|
26
|
+
const fetchData = async (signal: AbortSignal, query: string) => {
|
|
27
|
+
const res = await fetch(`/api/search?q=${query}`, { signal });
|
|
28
|
+
return res.json();
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function SearchComponent() {
|
|
32
|
+
const { run, data, loading, error } = useAbort(fetchData);
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
run(searchQuery);
|
|
36
|
+
}, [searchQuery]);
|
|
37
|
+
|
|
38
|
+
if (loading) return <div>Loading...</div>;
|
|
39
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
40
|
+
return <div>{data?.results}</div>;
|
|
41
|
+
}
|
|
23
42
|
```
|
|
24
43
|
|
|
25
|
-
|
|
26
|
-
|
|
44
|
+
That's it! Just 3 steps: define your async function, use the hook, call `run()`.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## The Problem
|
|
49
|
+
|
|
50
|
+
**Without `use-abort`, search inputs cause race conditions:**
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
// ❌ BROKEN: Race condition - slower responses overwrite newer ones!
|
|
54
|
+
function SearchBox() {
|
|
55
|
+
const [query, setQuery] = useState("");
|
|
56
|
+
const [results, setResults] = useState(null);
|
|
57
|
+
const [loading, setLoading] = useState(false);
|
|
58
|
+
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (!query) return;
|
|
61
|
+
|
|
62
|
+
setLoading(true);
|
|
63
|
+
fetch(`/api/search?q=${query}`)
|
|
64
|
+
.then((res) => res.json())
|
|
65
|
+
.then((data) => {
|
|
66
|
+
setResults(data); // ⚠️ Problem: Old request can overwrite new results!
|
|
67
|
+
setLoading(false);
|
|
68
|
+
});
|
|
69
|
+
}, [query]);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div>
|
|
73
|
+
<input value={query} onChange={(e) => setQuery(e.target.value)} />
|
|
74
|
+
{loading && <div>Loading...</div>}
|
|
75
|
+
{results && <div>{results.length} results</div>}
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
27
79
|
```
|
|
28
80
|
|
|
29
|
-
|
|
81
|
+
**What goes wrong:**
|
|
82
|
+
|
|
83
|
+
1. User types "react" → Request A sent (takes 2000ms)
|
|
84
|
+
2. User types "vue" → Request B sent (takes 500ms)
|
|
85
|
+
3. Request B finishes first → Shows Vue results ✅
|
|
86
|
+
4. Request A finishes late → **Overwrites with React results** ❌
|
|
30
87
|
|
|
31
|
-
|
|
88
|
+
**Result:** UI shows wrong data! User typed "vue" but sees "react" results.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## The Solution
|
|
93
|
+
|
|
94
|
+
**With `use-abort`, requests are automatically cancelled:**
|
|
32
95
|
|
|
33
96
|
```tsx
|
|
97
|
+
// ✅ FIXED: Previous requests auto-cancelled, no race conditions!
|
|
34
98
|
import { useAbort } from "use-abort";
|
|
35
99
|
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
if (!response.ok) throw new Error("Failed to fetch user");
|
|
40
|
-
return response.json();
|
|
100
|
+
const searchAPI = async (signal: AbortSignal, query: string) => {
|
|
101
|
+
const res = await fetch(`/api/search?q=${query}`, { signal });
|
|
102
|
+
return res.json();
|
|
41
103
|
};
|
|
42
104
|
|
|
43
|
-
function
|
|
44
|
-
const
|
|
105
|
+
function SearchBox() {
|
|
106
|
+
const [query, setQuery] = useState("");
|
|
107
|
+
const { run, data, loading } = useAbort(searchAPI);
|
|
45
108
|
|
|
46
109
|
useEffect(() => {
|
|
47
|
-
run(
|
|
48
|
-
}, [
|
|
110
|
+
if (query) run(query); // Auto-cancels previous request!
|
|
111
|
+
}, [query]);
|
|
49
112
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
113
|
+
return (
|
|
114
|
+
<div>
|
|
115
|
+
<input value={query} onChange={(e) => setQuery(e.target.value)} />
|
|
116
|
+
{loading && <div>Loading...</div>}
|
|
117
|
+
{data && <div>{data.length} results</div>}
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
54
120
|
}
|
|
55
121
|
```
|
|
56
122
|
|
|
57
|
-
|
|
123
|
+
**What happens now:**
|
|
124
|
+
|
|
125
|
+
1. User types "react" → Request A sent
|
|
126
|
+
2. User types "vue" → **Request A cancelled** → Request B sent
|
|
127
|
+
3. Request B finishes → Shows Vue results ✅
|
|
128
|
+
4. Request A already cancelled → Doesn't update anything ✅
|
|
129
|
+
|
|
130
|
+
**Result:** UI always shows correct data! 🎉
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## More Examples
|
|
135
|
+
|
|
136
|
+
### Debounced Search with Manual Cancel
|
|
58
137
|
|
|
59
138
|
```tsx
|
|
60
139
|
import { useAbort } from "use-abort";
|
|
@@ -245,4 +324,4 @@ MIT
|
|
|
245
324
|
|
|
246
325
|
## Contributing
|
|
247
326
|
|
|
248
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
327
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "use-abort",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A React hook for safely handling async API calls with AbortController",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -37,6 +37,6 @@
|
|
|
37
37
|
},
|
|
38
38
|
"repository": {
|
|
39
39
|
"type": "git",
|
|
40
|
-
"url": "https://github.com/
|
|
40
|
+
"url": "https://github.com/SURAJ-SHARMA27/use-abort"
|
|
41
41
|
}
|
|
42
42
|
}
|