×

什么是Axios?和React结合能解决啥问题?

作者:Terry2025.12.29来源:Web前端之家浏览:27评论:0
关键词:AxiosReact

不少刚接触React开发的同学,总会纠结「Axios和React到底咋配合?项目里发请求、处理数据要注意啥?」其实Axios是前端圈常用的HTTP客户端,和React结合能高效解决数据请求、状态同步这些核心需求,这篇文章把大家常问的Axios+React问题拆成8个关键话题,从基础到进阶一次讲透,帮你踩稳前端数据请求的坑~

Axios是基于Promise的HTTP请求库,能在浏览器和Node.js环境发请求,天生支持请求拦截、响应拦截、取消请求、自动转换JSON数据等实用功能。

React作为UI渲染库,核心逻辑是“数据驱动视图”——拿到后端数据后,通过useState useEffect这类hooks更新状态,进而触发UI重新渲染,Axios则负责帮React“拿数据”:比如做商品列表页时,Axios请求接口拿到商品数据,setState更新列表数组,页面就自动渲染新内容。

二者结合后,能解决三类核心问题:

  • 请求统一管理:给所有请求加token、统一设置接口前缀(baseURL),用拦截器一次配置全局生效;

  • 错误高效拦截:后端返回401(token过期)时自动跳登录页、网络超时自动提示,无需每个请求重复写逻辑;

  • 请求模式优化:多个接口并发请求(如同时拿用户信息和购物车数据)、先调A接口再调B接口(顺序请求),提升页面加载体验。

React项目里怎么引入Axios?基础配置咋做?

第一步先装依赖:在项目根目录执行 npm install axios(或yarn/pnpm)。

实际开发中,不建议直接用全局的axios,而是创建“自定义实例”——把baseURL、超时时间、请求头等通用配置集中管理,避免重复代码,示例如下:

// 新建 utils/request.js
import axios from 'axios';
// 创建axios实例,配置通用项
const request = axios.create({
  baseURL: process.env.REACT_APP_API_BASE, // 从环境变量拿接口前缀,区分开发/生产环境
  timeout: 5000, // 请求超时时间(毫秒),超过则报错
  headers: { 'Content-Type': 'application/json' } // 默认请求头
});
export default request;

之后在组件里导入该实例发请求,以用户列表组件为例:

import React, { useState, useEffect } from 'react';
import request from './utils/request'; // 导入自定义实例
function UserList() {
  const [users, setUsers] = useState([]); // 存用户列表数据
  // 组件挂载时发请求
  useEffect(() => {
    request.get('/users') // 接口路径自动拼接baseURL
      .then(res => {
        setUsers(res.data); // Axios自动把响应转成JSON,直接拿res.data
      })
      .catch(err => {
        console.error('请求失败原因:', err);
      });
  }, []); // 依赖空数组,仅组件挂载时执行
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

这样做的好处是,后续修改接口前缀(如从测试环境切生产),仅需调整REACT_APP_API_BASE环境变量;所有请求的超时时间、请求头需调整时,也只需修改request.js配置,无需逐个改动组件。

组件里用Axios发请求,怎么处理异步和状态更新?

React中发请求涉及“异步操作”与“状态更新”,最易踩的坑是“组件卸载后仍更新状态”(如快速切换页面时,旧请求的回调仍执行,触发setState会报错),分享两个实用技巧:

技巧1:用标记位避免卸载后更新状态

useEffect里加“组件是否挂载”的标记,请求成功后判断标记再更新状态:

useEffect(() => {
  let isMounted = true; // 标记组件是否在页面上
  request.get('/user/detail')
    .then(res => {
      if (isMounted) { // 组件未卸载才更新状态
        setUser(res.data);
      }
    })
    .catch(err => {
      if (isMounted) {
        console.error('请求失败:', err);
      }
    });
  return () => { 
    isMounted = false; // 组件卸载时,将标记设为false
  };
}, []);

技巧2:用Axios的“取消请求”功能

Axios支持通过CancelToken取消请求,组件卸载时主动取消未完成请求,避免回调执行:

useEffect(() => {
  const source = axios.CancelToken.source(); // 创建取消令牌
  request.get('/user/detail', {
    cancelToken: source.token // 把令牌传给请求配置
  })
  .then(res => {
    setUser(res.data);
  })
  .catch(err => {
    if (axios.isCancel(err)) { // 判断是否为主动取消的请求
      console.log('请求被取消啦~');
    } else {
      console.error('真·请求失败:', err);
    }
  });
  return () => { 
    source.cancel('组件卸载,取消请求'); // 组件卸载时取消请求
  };
}, []);

请求依赖项需写对:若某个状态(如用户ID)变化时需重新请求,要将该状态放入useEffect的依赖数组,比如根据用户选择的分类ID获取商品列表:

useEffect(() => {
  request.get(`/goods?categoryId=${categoryId}`)
    .then(res => setGoods(res.data));
}, [categoryId]); // categoryId变化时,重新发请求

Axios拦截器在React权限管理、请求加token这些场景咋用?

拦截器分“请求拦截器”(发请求前处理)和“响应拦截器”(收到响应后处理),在权限管理、统一加token场景中十分实用。

场景1:给所有请求自动加token

很多项目需用户登录后,给请求头加Authorization(如Bearer token),用请求拦截器统一处理:

// 在 utils/request.js 里配置
request.interceptors.request.use(config => {
  const token = localStorage.getItem('token'); // 从localStorage取token
  if (token) {
    config.headers.Authorization = `Bearer ${token}`; // 加到请求头
  }
  return config; // 放行请求
}, error => {
  return Promise.reject(error); // 抛出错误
});

所有通过request实例发的请求,都会自动带上token,无需每个请求手动编写。

场景2:响应拦截处理401(token过期跳登录)

后端返回401通常代表“登录态失效”,需跳转到登录页并清除旧token,用响应拦截器统一处理:

request.interceptors.response.use(
  response => response, // 响应正常时,直接返回给业务代码
  error => {
    if (error.response?.status === 401) { // 响应存在且状态码为401
      // 跳转到登录页(假设用react-router的useNavigate)
      // 注意:拦截器文件(如request.js)非React组件,不能直接用hooks!后续讲解决方案
      const navigate = useNavigate(); 
      navigate('/login'); 
      localStorage.removeItem('token'); // 清除旧token
    }
    return Promise.reject(error.response?.data); // 把错误信息抛给业务组件
  }
);

这里的关键问题是拦截器文件(如request.js)不是React组件,无法直接使用useNavigate这类hooks,解决方案有二:

  • 方案1:在拦截器里抛“事件”,通过自定义hook或事件总线,让组件层处理跳转;

  • 方案2:将跳转逻辑放在业务组件的catch里(但会重复代码,不推荐)。

更优雅的做法是在拦截器里抛错误,然后在全局错误处理组件中监听401并跳转,或封装“错误处理函数”在组件里调用。

多个请求并发、顺序请求在React里咋用Axios实现?

实际开发中,“同时请求多个接口”与“先调A再调B”很常见,Axios结合Promise API可轻松实现。

并发请求:Promise.all

若页面需同时获取“用户信息”和“权限列表”,待两个接口都成功后再渲染,可这样写:

useEffect(() => {
  Promise.all([
    request.get('/user/info'),
    request.get('/user/permissions')
  ])
  .then(([userRes, permRes]) => { // 数组解构,按顺序拿到两个响应
    setUser(userRes.data);
    setPermissions(permRes.data);
  })
  .catch(err => {
    console.error('至少有一个请求失败:', err);
  });
}, []);

只要有一个请求失败,Promise.all就会进入catch,适合“所有接口成功才渲染”的场景。

顺序请求:async/await

若需“先获取用户ID,再根据ID拿详情”,需保证顺序执行:

useEffect(() => {
  const fetchData = async () => {
    try {
      const userIdRes = await request.get('/user/currentId'); // 第一步:拿ID
      const userDetailRes = await request.get(`/user/${userIdRes.data.id}`); // 第二步:拿详情
      setUser(userDetailRes.data);
    } catch (err) {
      console.error('请求失败:', err);
    }
  };
  fetchData(); // 调用异步函数
}, []);

这种写法逻辑更线性,适合有依赖关系的请求链。

处理错误(网络错误、后端返回错误)在React里有啥技巧?

Axios的错误分两类:网络错误(如断网、请求超时)和后端业务错误(如参数错误、500服务器错误),需针对性处理:

第一步:区分错误类型

catch里通过err.isAxiosError判断是否为Axios封装的错误,再细分处理:

request.get('/data')
  .then(res => { /* 成功逻辑 */ })
  .catch(err => {
    if (err.isAxiosError) { // 是Axios的错误
      if (!err.response) { 
        // 无response,为网络错误(超时、断网)
        setErrorMsg('网络开小差了,检查下Wi-Fi~');
      } else { 
        // 有response,为后端返回的业务错误(4xx、5xx)
        setErrorMsg(err.response.data.msg || '服务器返回错误');
      }
    } else { 
      // 非Axios错误(如代码里手动throw)
      setErrorMsg('未知错误');
    }
  });

第二步:在组件里展示错误

将错误信息存在状态里,用JSX渲染:

function DataComponent() {
  const [errorMsg, setErrorMsg] = useState('');
  // ...请求逻辑
  return (
    <div>
      {errorMsg && (
        <div className="error-popup">
          {errorMsg}
        </div>
      )}
      {/* 其他UI内容 */}
    </div>
  );
}

第三步:封装错误处理函数(可选)

若多个组件需处理错误,可写通用函数:

// utils/handleError.js
export function handleAxiosError(err, setErrorMsg) {
  if (err.isAxiosError) {
    if (!err.response) {
      setErrorMsg('网络连接失败,请重试~');
    } else {
      setErrorMsg(err.response.data.msg || '请求出错了~');
    }
  } else {
    setErrorMsg('系统错误,请联系管理员~');
  }
}

组件里直接调用:

.catch(err => {
  handleAxiosError(err, setErrorMsg);
});

服务端渲染(SSR)的React项目用Axios要注意啥?

若使用Next.js这类SSR框架,Axios在服务端和客户端的表现有差异,需解决两个核心问题:

问题1:服务端无浏览器的XMLHttpRequest

Axios在Node.js环境发请求,默认用http模块,目前Axios已内置Node.js支持,项目中装了axios后,服务端可直接使用。

问题2:避免“请求数据污染”

服务端渲染时,同一台服务器会处理多个用户的请求,若用全局Axios实例,多个请求会共享配置(如cookie、token),导致“用户A的请求拿到用户B的数据”。

解决方案:为每个请求创建独立的Axios实例,以Next.js为例:

// utils/axios.js
import axios from 'axios';
import { NextPageContext } from 'next';
export function createAxiosInstance(ctx?: NextPageContext) {
  const instance = axios.create({
    baseURL: process.env.API_BASE,
  });
  // 服务端时,将请求的cookie传给Axios(保持用户登录态)
  if (ctx && ctx.req) {
    instance.defaults.headers.Cookie = ctx.req.headers.cookie;
  }
  return instance;
}

之后在页面的getServerSideProps(服务端渲染函数)和组件里分别使用:

// 服务端渲染时用
export async function getServerSideProps(context) {
  const request = createAxiosInstance(context); // 传入context,携带cookie
  const res = await request.get('/api/user');
  return {
    props: { user: res.data }
  };
}
// 客户端渲染时用
function UserPage({ user }) {
  const [moreData, setMoreData] = useState([]);
  useEffect(() => {
    const request = createAxiosInstance(); // 客户端实例,不携带context
    request.get('/api/more').then(res => setMoreData(res.data));
  }, []);
  return <div>{/* 渲染内容 */}</div>;
}

这样每个请求都有独立实例,避免数据串用。

有没有替代Axios的方案?和fetch比有啥优势?

若觉得Axios过重,或想尝试其他方案,可参考以下选择:

方案1:原生fetch API

fetch是浏览器内置的请求API,优点是“无依赖”(无需装包),但缺点也很明显:

  • 需手动处理JSON转换(res.json());

  • 错误处理不友好(仅网络错误会reject,4xx、5xx状态码仍会resolve);

  • 无拦截器,需自行封装;

  • 取消请求需手动用AbortController,代码更繁琐。

适合极小项目或需完全掌控请求细节的场景。

方案2:React Query / SWR

二者是“数据请求+状态管理”的上层库,不仅能发请求,还能实现缓存、后台同步、自动重新请求、请求节流等,以React Query为例:

import { useQuery } from 'react-query';
function UserList() {
  const { data, error, isLoading } = useQuery('users', () => 
    fetch('/api/users').then(res => res.json())
  );
  if (isLoading) return <div>加载中...</div>;
  if (error) return <div>请求失败</div>;
  return <ul>{data.map(user => <li>{user.name}</li>)}</ul>;
}

这类库适合中大型项目,数据逻辑复杂、需精细控制缓存和请求状态的场景,但简单项目中,Axios+React hooks的组合更轻量。

Axios和fetch核心差异总结

对比项Axiosfetch
依赖需安装(npm包)浏览器/Node.js内置
JSON转换自动转(res.data直接是对象)需手动res.json()
错误处理4xx/5xx会reject仅网络错误reject,状态码不管
拦截器内置请求/响应拦截器需自行封装
取消请求CancelToken(已弃用,用AbortController)AbortController

看完这8个问题,是不是对Axios+React的配合更清晰了?记住核心逻辑:Axios负责“高效拿数据”,React负责“优雅渲UI”,两者结合时重点处理异步状态、错误拦截、请求模式这三类问题,如果是新手,先从自定义Axios实例、useEffect发请求练起;项目复杂后,再尝试拦截器、并发请求、SSR适配这些进阶技巧~

您的支持是我们创作的动力!
温馨提示:本文作者系Terry ,经Web前端之家编辑修改或补充,转载请注明出处和本文链接:
https://www.jiangweishan.com/article/anixjsg234235232134.html

网友评论文明上网理性发言 已有0人参与

发表评论: