You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中RTK Query简易解析:是否替代Axios及表单交互实践

RTK Query 简易解释 + 实战代码示例

一、RTK Query 到底是什么?会替代 Axios 吗?

RTK Query 是 Redux Toolkit 自带的数据获取与缓存管理工具,本质是对底层 HTTP 客户端(比如 Axios、fetch)的上层封装——它不会替代 Axios,反而可以搭配 Axios 使用。

你可以把它理解成一个“懒人工具”:平时用 Axios 发请求,你得自己写请求逻辑、处理加载/成功/失败状态、手动管理缓存、写 Redux 状态同步代码;而 RTK Query 把这些重复工作全帮你做了,你只需要定义好请求的端点,剩下的状态、缓存、更新逻辑它自动搞定。

二、实战:React 表单 + Spring Boot 后端的完整流程

我们就用你说的场景:用户填表单提交数据到 Spring Boot 后端存库,之后能通过 CustID 查询数据。下面是具体代码实现:

1. 先配置 RTK Query 的 API 切片

首先装依赖:

npm install @reduxjs/toolkit react-redux

创建 src/services/customerApi.js,这里定义和后端交互的两个接口:提交客户、查询客户:

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

// 创建 API 切片,底层用 fetch(也可以换成 Axios,后面附示例)
export const customerApi = createApi({
  reducerPath: 'customerApi', // 唯一标识,存在 Redux Store 里的键名
  baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:8080/api/' }), // 你的 Spring Boot 后端地址
  endpoints: (builder) => ({
    // 提交客户数据的 POST 请求
    addCustomer: builder.mutation({
      query: (customerData) => ({
        url: 'customers',
        method: 'POST',
        body: customerData,
      }),
    }),
    // 根据 CustID 查询客户的 GET 请求
    getCustomerById: builder.query({
      query: (custId) => `customers/${custId}`,
    }),
  }),
});

// RTK Query 自动生成的 Hooks,直接在组件里用就行
export const { useAddCustomerMutation, useGetCustomerByIdQuery } = customerApi;

如果想用 Axios 代替默认的 fetch,只需要自定义一个 baseQuery:

import axios from 'axios';
import { createApi } from '@reduxjs/toolkit/query/react';

// 自定义 Axios 版的 baseQuery
const axiosBaseQuery = async ({ url, method, body }) => {
  try {
    const result = await axios({
      url: `http://localhost:8080/api/${url}`,
      method,
      data: body,
    });
    return { data: result.data };
  } catch (err) {
    return { error: { status: err.response.status, data: err.response.data } };
  }
};

// 剩下的和上面一样,只是把 baseQuery 换成自定义的
export const customerApi = createApi({
  reducerPath: 'customerApi',
  baseQuery: axiosBaseQuery,
  endpoints: (builder) => ({
    addCustomer: builder.mutation({
      query: (customerData) => ({
        url: 'customers',
        method: 'POST',
        body: customerData,
      }),
    }),
    getCustomerById: builder.query({
      query: (custId) => `customers/${custId}`,
    }),
  }),
});

export const { useAddCustomerMutation, useGetCustomerByIdQuery } = customerApi;

2. 配置 Redux Store

创建 src/app/store.js,把 RTK Query 的 reducer 加到 Store 里:

import { configureStore } from '@reduxjs/toolkit';
import { customerApi } from '../services/customerApi';

export const store = configureStore({
  reducer: {
    // 把 RTK Query 的 reducer 注册到 Store
    [customerApi.reducerPath]: customerApi.reducer,
  },
  // 必须加这个中间件,处理缓存、请求失效等逻辑
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(customerApi.middleware),
});

3. 在根组件里提供 Store

修改 src/App.js,用 Provider 把 Store 传给所有子组件:

import { Provider } from 'react-redux';
import { store } from './app/store';
import CustomerForm from './components/CustomerForm';
import CustomerQuery from './components/CustomerQuery';

function App() {
  return (
    <Provider store={store}>
      <div style={{ maxWidth: 600, margin: '2rem auto', padding: '0 1rem' }}>
        <h1>客户管理系统</h1>
        <CustomerForm />
        <hr />
        <CustomerQuery />
      </div>
    </Provider>
  );
}

export default App;

4. 实现表单提交组件

创建 src/components/CustomerForm.js,处理用户输入和提交:

import { useState } from 'react';
import { useAddCustomerMutation } from '../services/customerApi';

function CustomerForm() {
  const [formData, setFormData] = useState({
    firstName: '',
    lastName: '',
    city: '',
    custID: '',
  });
  // 用 RTK Query 生成的 mutation Hook,返回[触发请求的函数, 请求状态]
  const [addCustomer, { isLoading, isSuccess, error }] = useAddCustomerMutation();

  // 处理表单输入变化
  const handleInputChange = (e) => {
    setFormData({ ...formData, [e.target.name]: e.target.value });
  };

  // 提交表单
  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      // unwrap() 可以直接拿到成功数据,或者抛出错误
      await addCustomer(formData).unwrap();
      // 提交成功后清空表单
      setFormData({ firstName: '', lastName: '', city: '', custID: '' });
    } catch (err) {
      console.error('提交失败:', err);
    }
  };

  return (
    <form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
      <div>
        <label style={{ display: 'block', marginBottom: '0.5rem' }}>FirstName:</label>
        <input
          type="text"
          name="firstName"
          value={formData.firstName}
          onChange={handleInputChange}
          required
          style={{ width: '100%', padding: '0.5rem' }}
        />
      </div>
      <div>
        <label style={{ display: 'block', marginBottom: '0.5rem' }}>LastName:</label>
        <input
          type="text"
          name="lastName"
          value={formData.lastName}
          onChange={handleInputChange}
          required
          style={{ width: '100%', padding: '0.5rem' }}
        />
      </div>
      <div>
        <label style={{ display: 'block', marginBottom: '0.5rem' }}>City:</label>
        <input
          type="text"
          name="city"
          value={formData.city}
          onChange={handleInputChange}
          required
          style={{ width: '100%', padding: '0.5rem' }}
        />
      </div>
      <div>
        <label style={{ display: 'block', marginBottom: '0.5rem' }}>CustID:</label>
        <input
          type="text"
          name="custID"
          value={formData.custID}
          onChange={handleInputChange}
          required
          style={{ width: '100%', padding: '0.5rem' }}
        />
      </div>
      <button
        type="submit"
        disabled={isLoading}
        style={{ padding: '0.7rem', backgroundColor: '#2196F3', color: 'white', border: 'none', borderRadius: '4px', cursor: 'pointer' }}
      >
        {isLoading ? '提交中...' : '提交客户数据'}
      </button>
      {isSuccess && <p style={{ color: '#4CAF50', margin: '0.5rem 0' }}>数据提交成功!</p>}
      {error && <p style={{ color: '#F44336', margin: '0.5rem 0' }}>提交失败: {error.data?.message || error.status}</p>}
    </form>
  );
}

export default CustomerForm;

5. 实现客户查询组件

创建 src/components/CustomerQuery.js,处理 CustID 查询:

import { useState } from 'react';
import { useGetCustomerByIdQuery } from '../services/customerApi';

function CustomerQuery() {
  const [custId, setCustId] = useState('');
  // 用 RTK Query 生成的 query Hook,自动处理请求和缓存
  const { data: customer, isLoading, error } = useGetCustomerByIdQuery(custId, {
    skip: !custId, // 当 CustID 为空时,不发送请求
  });

  return (
    <div>
      <h2>查询客户信息</h2>
      <input
        type="text"
        placeholder="请输入 CustID"
        value={custId}
        onChange={(e) => setCustId(e.target.value)}
        style={{ width: '100%', padding: '0.5rem', margin: '1rem 0' }}
      />
      {isLoading && <p style={{ color: '#666' }}>加载中...</p>}
      {error && <p style={{ color: '#F44336' }}>查询失败: {error.data?.message || error.status}</p>}
      {customer && (
        <div style={{ border: '1px solid #eee', padding: '1rem', borderRadius: '4px' }}>
          <h3>客户详情</h3>
          <p><strong>FirstName:</strong> {customer.firstName}</p>
          <p><strong>LastName:</strong> {customer.lastName}</p>
          <p><strong>City:</strong> {customer.city}</p>
          <p><strong>CustID:</strong> {customer.custID}</p>
        </div>
      )}
    </div>
  );
}

export default CustomerQuery;

三、RTK Query 在这个流程里的具体角色

  1. 请求封装:不用你手写 Axios/fetch 请求,定义一次端点,就能在组件里用 Hook 直接调用
  2. 状态自动管理:自动提供 isLoading、isSuccess、error 这些状态,不用你自己在 Redux 里写 Action 和 Reducer
  3. 缓存优化:同一个 CustID 多次查询时,直接返回缓存数据,不用重复发请求;如果数据更新了,会自动刷新缓存
  4. 简化组件逻辑:组件只需要关注表单交互和数据展示,不用手动处理请求的生命周期(比如开始请求时设 loading,成功后清状态)

内容的提问来源于stack exchange,提问作者Dips

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 09:57:03