useAxios:使用 axios 调用 API 的简单自定义钩子

2025-05-24

useAxios:使用 axios 调用 API 的简单自定义钩子

大家好,

如果没有 API 调用,前端应用就不完整,调用 API 会变得有些重复。为此,我们可以创建一个自定义钩子,省去这种重复操作。从前端进行 API 调用,常用的方法有fetchaxios。由于 Axios 支持拦截器等功能,我们将在此钩子中使用它们。

我们将按照以下步骤创建useAxios 钩子
- 1. 使用 axios 从组件执行 API 调用。2
. 添加 API 响应、加载和错误状态。3
. 使用以上所有方法创建一个用于调用 API 的钩子。4
. 使钩子动态化,以调用所有类型的 API 方法。

如果您不想执行这些步骤并直接跳到最终代码,请查看此处

现在,让我们一步一步深入创建我们的自定义钩子!

1. 从组件进行简单的 API 调用

为了创建此示例,我们将使用jsonplaceholder 的posts api。他们还创建了更多类似的 API,用于练习。

通常,一个应用程序的所有 API 都具有相同的基本 URL。我们将首先为 axios 设置基本 URL,这样就无需反复传递它。如果您使用多个基本 URL,axios 可以通过创建实例来支持。您可以查看其文档

在我们的 App 组件中,我们只需调用一个getAPI 来获取帖子列表。为此,我们使用了useEffect钩子。App 组件的基本 API 调用如下所示:

//App Component

import { useEffect } from 'react';
import axios from 'axios';

axios.defaults.baseURL = 'https://jsonplaceholder.typicode.com';

const App = () => {
    const fetchData = () => {
        axios
            .get('/posts')
            .then((res) => {
                console.log(res);
            })
            .catch((err) => {
                console.log(err);
            });
    };

    useEffect(() => {
        fetchData();
    }, []);

    return (
          <div className='app'>
              //do something
          </div>
       );
};

export default App;

Enter fullscreen mode Exit fullscreen mode

上面的 API 调用很简单。我们以前axios.get调用 API 时,会使用 Promise 来获取结果或错误。因为我们已经设置了 baseURL,所以我们只需将具体路径传递给 axios 方法即可。

2. 向 API 调用添加不同的状态

但到目前为止,我们只是记录来自 API 的响应。让我们使用 React 的状态来保存响应和错误(如果发生)。此外,我们将添加一个加载状态,以便有条件地在页面上显示加载器。

// App Component

import { useState, useEffect } from 'react';
import axios from 'axios';

axios.defaults.baseURL = 'https://jsonplaceholder.typicode.com';

const App = () => {
    const [response, setResponse] = useState(null);
    const [error, setError] = useState('');
    const [loading, setloading] = useState(true);

    const fetchData = () => {
        axios
            .get('/posts')
            .then((res) => {
                setResponse(res.data);
            })
            .catch((err) => {
                setError(err);
            })
            .finally(() => {
                setloading(false);
            });
    };

    useEffect(() => {
        fetchData();
    }, []);

    return (
        <div className='app'>
            //do something
        </div>
    );
};

export default App;

Enter fullscreen mode Exit fullscreen mode

3. 创建自定义钩子

自定义钩子一开始可能会让人不知所措。但是,如果你像其他组件一样看待它们,它们会更有意义。需要记住的是,自定义钩子只是另一个组件,它返回值而不是 JSX 。这是我对自定义钩子的定义,不知何故,它让我对这个概念更加清晰了。你可以在这里阅读更多关于自定义钩子的内容

现在,让我们将调用 API 的逻辑从应用组件复制到自定义钩子中。因此,我们的初稿useAxios大致如下:

// useAxios hook (first draft)

import { useState, useEffect } from 'react';
import axios from 'axios';

axios.defaults.baseURL = 'https://jsonplaceholder.typicode.com';

const useAxios = () => {
    const [response, setResponse] = useState(null);
    const [error, setError] = useState('');
    const [loading, setloading] = useState(true);

    const fetchData = () => {
        axios
            .get('/posts')
            .then((res) => {
                setResponse(res.data);
            })
            .catch((err) => {
                setError(err);
            })
            .finally(() => {
                setloading(false);
            });
    };

    useEffect(() => {
        fetchData();
    }, []);

    // custom hook returns value
    return { response, error, loading };
};

export default useAxios;

Enter fullscreen mode Exit fullscreen mode

如果你仔细观察,就会发现我们实际上是复制粘贴了代码,并创建了一个自定义钩子。唯一的区别是,这个钩子返回了三个值:加载、响应和错误。

到目前为止,一切看起来都很好,但我们创建的钩子根本不是动态的。如果我们需要更改 API 路径,或者我们想使用 post 调用而不是 get 调用,那么我们现在无法做到。

因此,这是使我们的钩子更加灵活的最后一步。 -

4. 让钩子更加动态

为了使钩子动态化,我们可以为 URL 路径创建一个变量,并将其作为 prop 传递给钩子。此外,axios 可以支持 get、put、post 和 delete 等方法。因此,我们也需要一个方法名变量。除了路径和方法之外,我们还将添加两个变量,用于将正文和标头传递给请求。添加完这些之后,我们的钩子将如下所示:

最终代码


// useAxios hook

import { useState, useEffect } from 'react';
import axios from 'axios';

axios.defaults.baseURL = 'https://jsonplaceholder.typicode.com';

const useAxios = ({ url, method, body = null, headers = null }) => {
    const [response, setResponse] = useState(null);
    const [error, setError] = useState('');
    const [loading, setloading] = useState(true);

    const fetchData = () => {
        axios[method](url, JSON.parse(headers), JSON.parse(body))
            .then((res) => {
                setResponse(res.data);
            })
            .catch((err) => {
                setError(err);
            })
            .finally(() => {
                setloading(false);
            });
    };

    useEffect(() => {
        fetchData();
    }, [method, url, body, headers]);

    return { response, error, loading };
};

export default useAxios;

Enter fullscreen mode Exit fullscreen mode

useAxios钩子已准备就绪,现在让我们将其应用于我们的应用组件,并尝试使用它创建新帖子。因此,该App组件将是 -


// App Component

const App = () => {
    const { response, loading, error } = useAxios({
        method: 'post',
        url: '/posts',
        headers: JSON.stringify({ accept: '*/*' }),
        body: JSON.stringify({
            userId: 1,
            id: 19392,
            title: 'title',
            body: 'Sample text',
        }),
    });
    const [data, setData] = useState([]);

    useEffect(() => {
        if (response !== null) {
            setData(response);
        }
    }, [response]);

    return (
        <div className='App'>
            <h1>Posts</h1>

            {loading ? (
                <p>loading...</p>
            ) : (
                <div>
                    {error && (
                        <div>
                            <p>{error.message}</p>
                        </div>
                    )}
                    <div>{data && <p>{data.id}</p>}</div>
                </div>
            )}
        </div>
    );
};

export default App;

Enter fullscreen mode Exit fullscreen mode

这是 useAxios hook 的最基础版本。您可以根据自己的需求添加更多自定义功能。

非常感谢你阅读这篇文章,也欢迎你分享你对这个自定义钩子的想法!此外,如果你喜欢我的文章,也可以在推特上关注我,或者请我喝杯咖啡,获取每日更新。

继续学习🙌

文章来源:https://dev.to/hey_yogini/useaxios-a-simple-custom-hook-for-calling-apis-using-axios-2dkj
PREV
useContext 实现更好的状态管理!1 2
NEXT
使用交叉观察器在 React 中实现无限滚动