axios-react-hook 1.0.0 → 2.0.0
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/LICENSE +21 -21
- package/README.md +152 -47
- package/package.json +27 -16
- package/src/useAxios.js +146 -33
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c)
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Muhammed Rashid
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,47 +1,152 @@
|
|
|
1
|
-
# axios-react-hook
|
|
2
|
-
|
|
3
|
-
A
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
##
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
1
|
+
# axios-react-hook
|
|
2
|
+
|
|
3
|
+
A lightweight React hook for Axios-based API calls with support for all HTTP methods.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/axios-react-hook)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
> **v2.0.0** — V2 is now the default import.
|
|
9
|
+
> Existing users on `^1.0.0` are **not affected** — npm never auto-upgrades across major versions.
|
|
10
|
+
> If you upgrade manually, see the [migration guide](#migrating-v1--v2) below.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
**Default (V2)**
|
|
17
|
+
- ✅ Object-based config — readable, no positional-arg juggling
|
|
18
|
+
- ✅ Query `params` serialised into the URL automatically
|
|
19
|
+
- ✅ Per-request `headers` and `timeout`
|
|
20
|
+
- ✅ `onSuccess` / `onError` callbacks
|
|
21
|
+
- ✅ `AbortController` cancellation — prevents race conditions and unmount warnings
|
|
22
|
+
- ✅ HTTP `status` code in return value
|
|
23
|
+
- ✅ `cancel()` to abort in-flight requests manually
|
|
24
|
+
- ✅ Supports GET, POST, PUT, PATCH, DELETE and more
|
|
25
|
+
- ✅ Auto-fetch on mount, manual trigger via `refetch()`
|
|
26
|
+
- ✅ Pass your own Axios instance
|
|
27
|
+
|
|
28
|
+
**V1** (still available at `axios-react-hook/v1`)
|
|
29
|
+
- ✅ Positional-argument API — unchanged since 1.0.0
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install axios-react-hook
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
### V2 (default)
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
import useAxios from 'axios-react-hook';
|
|
47
|
+
|
|
48
|
+
function Posts() {
|
|
49
|
+
const { data, loading, error, status } = useAxios({
|
|
50
|
+
url: 'https://jsonplaceholder.typicode.com/posts',
|
|
51
|
+
params: { _limit: 10 },
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (loading) return <p>Loading…</p>;
|
|
55
|
+
if (error) return <p>{status} — {error.message}</p>;
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<ul>
|
|
59
|
+
{data.map(post => <li key={post.id}>{post.title}</li>)}
|
|
60
|
+
</ul>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### V1 (legacy)
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
import useAxios from 'axios-react-hook/v1';
|
|
69
|
+
|
|
70
|
+
function Posts() {
|
|
71
|
+
const { data, loading, error } = useAxios(
|
|
72
|
+
'https://jsonplaceholder.typicode.com/posts'
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
if (loading) return <p>Loading…</p>;
|
|
76
|
+
if (error) return <p>Error: {error.message}</p>;
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<ul>
|
|
80
|
+
{data.map(post => <li key={post.id}>{post.title}</li>)}
|
|
81
|
+
</ul>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Import paths
|
|
89
|
+
|
|
90
|
+
| Import path | API | Who should use it |
|
|
91
|
+
|-----------------------|--------|-----------------------------------------|
|
|
92
|
+
| `axios-react-hook` | **V2** | Everyone on a fresh install / new code |
|
|
93
|
+
| `axios-react-hook/v2` | V2 | Explicit V2 import (same as default) |
|
|
94
|
+
| `axios-react-hook/v1` | V1 | Users who upgraded and need the old API |
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## API Reference
|
|
99
|
+
|
|
100
|
+
### V2 Options
|
|
101
|
+
|
|
102
|
+
| Option | Type | Default | Description |
|
|
103
|
+
|-------------|-----------------|----------|---------------------------------------------------------|
|
|
104
|
+
| `url` | `string` | — | Request URL *(required)* |
|
|
105
|
+
| `method` | `string` | `'get'` | HTTP method: `get` `post` `put` `patch` `delete` |
|
|
106
|
+
| `body` | `any` | `null` | Request body (POST / PUT / PATCH / DELETE) |
|
|
107
|
+
| `params` | `object` | `null` | URL query parameters e.g. `{ page: 1, limit: 10 }` |
|
|
108
|
+
| `headers` | `object` | `null` | Per-request headers |
|
|
109
|
+
| `timeout` | `number` | `0` | Request timeout in ms (`0` = no timeout) |
|
|
110
|
+
| `auto` | `boolean` | `true` | Auto-fire on mount and whenever config changes |
|
|
111
|
+
| `instance` | `AxiosInstance` | `axios` | Custom axios instance |
|
|
112
|
+
| `onSuccess` | `Function` | `null` | Called with `(data, response)` on success |
|
|
113
|
+
| `onError` | `Function` | `null` | Called with `(error)` on failure |
|
|
114
|
+
|
|
115
|
+
### V2 Return value
|
|
116
|
+
|
|
117
|
+
| Key | Type | Description |
|
|
118
|
+
|-----------|------------|----------------------------------------------|
|
|
119
|
+
| `data` | `any` | Response payload |
|
|
120
|
+
| `loading` | `boolean` | `true` while a request is in flight |
|
|
121
|
+
| `error` | `Error` | Error from the last failed request |
|
|
122
|
+
| `status` | `number` | HTTP status code (`200`, `404`, …) or `null` |
|
|
123
|
+
| `refetch` | `Function` | Manually trigger the request |
|
|
124
|
+
| `cancel` | `Function` | Cancel the currently in-flight request |
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Migrating V1 → V2
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
// Before (V1)
|
|
132
|
+
import useAxios from 'axios-react-hook/v1';
|
|
133
|
+
const { data, loading, error, refetch } = useAxios(url, method, body, auto, instance);
|
|
134
|
+
|
|
135
|
+
// After (V2)
|
|
136
|
+
import useAxios from 'axios-react-hook';
|
|
137
|
+
const { data, loading, error, status, refetch, cancel } = useAxios({
|
|
138
|
+
url, method, body, auto, instance,
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Changelog
|
|
145
|
+
|
|
146
|
+
See [CHANGELOG.md](./CHANGELOG.md).
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## License
|
|
151
|
+
|
|
152
|
+
MIT © [Muhammed Rashid](https://github.com/devmdrd)
|
package/package.json
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "axios-react-hook",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "A lightweight React hook for Axios-based API calls with support for all HTTP methods.",
|
|
5
|
-
"main": "src/useAxios.js",
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "axios-react-hook",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "A lightweight React hook for Axios-based API calls with support for all HTTP methods.",
|
|
5
|
+
"main": "src/useAxios.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"src",
|
|
8
|
+
"README.md",
|
|
9
|
+
"LICENSE"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": "./src/useAxios.js"
|
|
13
|
+
},
|
|
14
|
+
"keywords": ["axios", "react", "hook", "api", "http", "fetch"],
|
|
15
|
+
"author": "Muhammed Rashid",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/devmdrd/axios-react-hook"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"axios": "^1.6.0"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"react": ">=16.8.0"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/useAxios.js
CHANGED
|
@@ -1,33 +1,146 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react';
|
|
2
|
-
import axios from 'axios';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
1
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* useAxios v2
|
|
6
|
+
*
|
|
7
|
+
* An improved React hook for HTTP requests with object-based config,
|
|
8
|
+
* automatic request cancellation, per-request headers/params/timeout,
|
|
9
|
+
* and success/error callbacks.
|
|
10
|
+
*
|
|
11
|
+
* @param {object} options
|
|
12
|
+
* @param {string} options.url - The request URL (required)
|
|
13
|
+
* @param {string} [options.method='get'] - HTTP method: get | post | put | patch | delete
|
|
14
|
+
* @param {any} [options.body=null] - Request body / payload (POST, PUT, PATCH, DELETE)
|
|
15
|
+
* @param {object} [options.params=null] - URL query parameters e.g. { page: 1, limit: 10 }
|
|
16
|
+
* @param {object} [options.headers=null] - Per-request headers merged on top of instance defaults
|
|
17
|
+
* @param {number} [options.timeout=0] - Request timeout in milliseconds (0 = no timeout)
|
|
18
|
+
* @param {boolean} [options.auto=true] - When true, fires on mount and whenever config changes
|
|
19
|
+
* @param {AxiosInstance} [options.instance=axios] - Custom axios instance (e.g. with interceptors or base URL)
|
|
20
|
+
* @param {Function} [options.onSuccess] - Called with (data, response) on a successful request
|
|
21
|
+
* @param {Function} [options.onError] - Called with (error) when the request fails
|
|
22
|
+
*
|
|
23
|
+
* @returns {{ data: any, loading: boolean, error: Error|null, status: number|null, refetch: Function, cancel: Function }}
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // Auto GET on mount
|
|
27
|
+
* const { data, loading, error, status } = useAxios({
|
|
28
|
+
* url: 'https://api.example.com/posts',
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* // GET with query params
|
|
33
|
+
* const { data } = useAxios({
|
|
34
|
+
* url: 'https://api.example.com/posts',
|
|
35
|
+
* params: { userId: 1, _limit: 5 },
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* // Manual POST with callbacks
|
|
40
|
+
* const { refetch } = useAxios({
|
|
41
|
+
* url: 'https://api.example.com/posts',
|
|
42
|
+
* method: 'post',
|
|
43
|
+
* body: { title: 'Hello', body: 'World' },
|
|
44
|
+
* auto: false,
|
|
45
|
+
* onSuccess: (data) => console.log('Created:', data),
|
|
46
|
+
* onError: (err) => console.error('Failed:', err.message),
|
|
47
|
+
* });
|
|
48
|
+
*/
|
|
49
|
+
export default function useAxios(options = {}) {
|
|
50
|
+
const {
|
|
51
|
+
url,
|
|
52
|
+
method = 'get',
|
|
53
|
+
body = null,
|
|
54
|
+
params = null,
|
|
55
|
+
headers = null,
|
|
56
|
+
timeout = 0,
|
|
57
|
+
auto = true,
|
|
58
|
+
instance = axios,
|
|
59
|
+
onSuccess = null,
|
|
60
|
+
onError = null,
|
|
61
|
+
} = options;
|
|
62
|
+
|
|
63
|
+
// ── State ──────────────────────────────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
const [data, setData] = useState(null);
|
|
66
|
+
// Only start in loading state when auto=true AND a URL is already provided
|
|
67
|
+
const [loading, setLoading] = useState(auto && !!url);
|
|
68
|
+
const [error, setError] = useState(null);
|
|
69
|
+
// HTTP status code of the last response (e.g. 200, 404) — null before first request
|
|
70
|
+
const [status, setStatus] = useState(null);
|
|
71
|
+
|
|
72
|
+
// Holds the AbortController for the currently in-flight request.
|
|
73
|
+
// Stored in a ref so changing it never triggers a re-render.
|
|
74
|
+
const abortRef = useRef(null);
|
|
75
|
+
|
|
76
|
+
// ── Cancel ─────────────────────────────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
// Stable reference (empty dep array) so it never causes fetch to re-create.
|
|
79
|
+
const cancel = useCallback(() => {
|
|
80
|
+
abortRef.current?.abort();
|
|
81
|
+
}, []);
|
|
82
|
+
|
|
83
|
+
// ── Fetch function ─────────────────────────────────────────────────────────
|
|
84
|
+
|
|
85
|
+
const fetch = useCallback(async () => {
|
|
86
|
+
if (!url) return; // guard — do nothing without a URL
|
|
87
|
+
|
|
88
|
+
// Cancel any previous in-flight request before starting a new one.
|
|
89
|
+
// This prevents stale responses from overwriting state (race condition fix).
|
|
90
|
+
cancel();
|
|
91
|
+
const controller = new AbortController();
|
|
92
|
+
abortRef.current = controller;
|
|
93
|
+
|
|
94
|
+
setLoading(true);
|
|
95
|
+
setError(null);
|
|
96
|
+
|
|
97
|
+
// Build the axios request config — only attach optional fields when provided
|
|
98
|
+
const config = {
|
|
99
|
+
url,
|
|
100
|
+
method: method.toLowerCase(),
|
|
101
|
+
signal: controller.signal, // ties this request to the AbortController
|
|
102
|
+
};
|
|
103
|
+
if (params) config.params = params;
|
|
104
|
+
if (body) config.data = body;
|
|
105
|
+
if (headers) config.headers = headers;
|
|
106
|
+
if (timeout > 0) config.timeout = timeout;
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const res = await instance.request(config);
|
|
110
|
+
setData(res.data);
|
|
111
|
+
setStatus(res.status);
|
|
112
|
+
onSuccess?.(res.data, res); // optional success callback
|
|
113
|
+
} catch (err) {
|
|
114
|
+
// Cancellation throws a CanceledError / AbortError — ignore it silently.
|
|
115
|
+
// We do NOT update state for cancelled requests.
|
|
116
|
+
if (err.name === 'CanceledError' || err.name === 'AbortError') return;
|
|
117
|
+
setError(err);
|
|
118
|
+
setStatus(err.response?.status ?? null); // null for network errors (no response)
|
|
119
|
+
onError?.(err); // optional error callback
|
|
120
|
+
} finally {
|
|
121
|
+
// Always clear loading — success, failure, or anything else
|
|
122
|
+
setLoading(false);
|
|
123
|
+
}
|
|
124
|
+
}, [url, method, body, params, headers, timeout, instance, onSuccess, onError, cancel]);
|
|
125
|
+
|
|
126
|
+
// ── Auto-fetch ─────────────────────────────────────────────────────────────
|
|
127
|
+
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
if (!url || !auto) return;
|
|
130
|
+
fetch();
|
|
131
|
+
// Cleanup: cancel the in-flight request if the component unmounts
|
|
132
|
+
// or if the config changes before the response arrives.
|
|
133
|
+
return () => cancel();
|
|
134
|
+
}, [fetch]); // fetch itself changes only when any config value changes
|
|
135
|
+
|
|
136
|
+
// ── Return ─────────────────────────────────────────────────────────────────
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
data,
|
|
140
|
+
loading,
|
|
141
|
+
error,
|
|
142
|
+
status,
|
|
143
|
+
refetch: fetch, // alias — same function, more intuitive name at the call site
|
|
144
|
+
cancel,
|
|
145
|
+
};
|
|
146
|
+
}
|