umi数据请求方案:axios、swr、react-query集成

umi数据请求方案:axios、swr、react-query集成

【免费下载链接】umi A framework in react community ✨ 【免费下载链接】umi 项目地址: https://gitcode.com/GitHub_Trending/um/umi

引言:为什么需要专业的数据请求方案?

在现代前端开发中,数据请求是应用的核心功能之一。传统的fetch API虽然基础,但在复杂业务场景下往往力不从心。umi作为React社区的主流框架,提供了多种数据请求方案的优雅集成方式。本文将深入探讨umi中axios、swr和react-query三大主流方案的集成与实践。

一、umi内置请求方案概览

1.1 内置请求能力

umi内置了基于fetch的请求方案,通过useRequest hook提供基础的数据请求功能:

import { useRequest } from 'umi';

export default function Page() {
  const { data, loading, error } = useRequest('/api/userInfo');
  
  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  
  return <div>Hello, {data.name}</div>;
}

1.2 配置请求基础配置

.umirc.tsconfig/config.ts中配置全局请求设置:

export default {
  request: {
    timeout: 10000,
    errorConfig: {
      errorPage: '/error',
    },
    requestInterceptors: [
      (url: string, options: any) => {
        // 添加认证token
        const token = localStorage.getItem('token');
        if (token) {
          options.headers.Authorization = `Bearer ${token}`;
        }
        return { url, options };
      },
    ],
    responseInterceptors: [
      (response: Response) => {
        // 统一处理响应
        return response;
      },
    ],
  },
};

二、axios集成方案

2.1 安装与配置

npm install axios

创建自定义请求实例:

// src/utils/request.ts
import axios from 'axios';

const request = axios.create({
  baseURL: '/api',
  timeout: 10000,
});

// 请求拦截器
request.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// 响应拦截器
request.interceptors.response.use(
  (response) => response.data,
  (error) => {
    if (error.response?.status === 401) {
      localStorage.removeItem('token');
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

export default request;

2.2 在组件中使用

import React, { useState, useEffect } from 'react';
import request from '@/utils/request';

const UserList: React.FC = () => {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchUsers = async () => {
      setLoading(true);
      try {
        const response = await request.get('/users');
        setUsers(response.data);
      } catch (error) {
        console.error('Failed to fetch users:', error);
      } finally {
        setLoading(false);
      }
    };

    fetchUsers();
  }, []);

  if (loading) return <div>Loading...</div>;

  return (
    <div>
      <h2>用户列表</h2>
      {users.map(user => (
        <div key={user.id}>{user.name}</div>
      ))}
    </div>
  );
};

三、SWR集成方案

3.1 安装与基础配置

npm install swr

3.2 基础使用示例

import useSWR from 'swr';

const fetcher = (url: string) => fetch(url).then(res => res.json());

const UserProfile: React.FC<{ userId: string }> = ({ userId }) => {
  const { data, error, isLoading } = useSWR(
    `/api/users/${userId}`,
    fetcher,
    {
      revalidateOnFocus: false,
      refreshInterval: 30000,
    }
  );

  if (error) return <div>Failed to load user</div>;
  if (isLoading) return <div>Loading...</div>;

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.email}</p>
    </div>
  );
};

3.3 高级特性应用

import useSWR, { mutate } from 'swr';

const TodoList: React.FC = () => {
  const { data: todos, error, isLoading } = useSWR('/api/todos', fetcher);

  const addTodo = async (title: string) => {
    const newTodo = { title, completed: false };
    
    // 乐观更新
    mutate('/api/todos', [...(todos || []), newTodo], false);
    
    try {
      await fetch('/api/todos', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(newTodo),
      });
      
      // 重新验证数据
      mutate('/api/todos');
    } catch (error) {
      // 回滚 optimistic update
      mutate('/api/todos');
    }
  };

  // 渲染逻辑...
};

四、React Query集成方案

4.1 安装与配置

npm install @tanstack/react-query

配置React Query客户端:

// app.ts
import { RuntimeReactQueryType } from 'umi';

export const reactQuery: RuntimeReactQueryType = {
  queryClient: {
    defaultOptions: {
      queries: {
        refetchOnWindowFocus: false,
        staleTime: 5 * 60 * 1000, // 5分钟
        cacheTime: 10 * 60 * 1000, // 10分钟
      },
    },
  },
  devtool: {
    position: 'bottom-left',
  },
};

4.2 基础查询使用

import { useQuery } from 'umi';

const GitHubStats: React.FC = () => {
  const { isFetching, data } = useQuery(
    ['repoData'], 
    () => fetch('https://api.github.com/repos/umijs/umi').then(res => res.json())
  );

  return (
    <div className="container">
      {isFetching && <p>Loading ...</p>}
      {data && <p>UmiJS has {data.stargazers_count} stars now!</p>}
    </div>
  );
};

4.3 变异(Mutation)操作

import { useQuery, useMutation } from 'umi';

const UserManager: React.FC = () => {
  const { data: users } = useQuery(['users'], fetchUsers);
  
  const deleteUserMutation = useMutation(
    (userId: string) => fetch(`/api/users/${userId}`, { method: 'DELETE' }),
    {
      onSuccess: () => {
        // 使users查询失效,触发重新获取
        queryClient.invalidateQueries(['users']);
      },
    }
  );

  const handleDelete = (userId: string) => {
    deleteUserMutation.mutate(userId);
  };

  return (
    <div>
      {users?.map(user => (
        <div key={user.id}>
          {user.name}
          <button onClick={() => handleDelete(user.id)}>
            Delete
          </button>
        </div>
      ))}
    </div>
  );
};

五、三种方案对比与选型指南

5.1 功能特性对比表

特性axiosSWRReact Query
缓存机制无内置自动缓存高级缓存策略
数据同步手动自动重验证自动后台更新
错误处理手动配置内置重试智能重试机制
开发工具简单调试强大DevTools
学习曲线简单中等较陡峭
包大小中等较大

5.2 选型建议

mermaid

5.3 性能考量因素

  1. 包大小影响:axios最小,React Query最大
  2. 内存占用:缓存策略会影响内存使用
  3. 网络请求优化:SWR和React Query有自动去重机制
  4. 渲染性能:合理的缓存可以减少不必要的重渲染

六、最佳实践与常见陷阱

6.1 错误处理统一方案

// 创建统一的错误处理hook
const useApi = () => {
  const [error, setError] = useState<Error | null>(null);

  const handleError = (err: any) => {
    const message = err.response?.data?.message || err.message || '请求失败';
    setError(new Error(message));
    // 可以在这里添加错误上报
  };

  const clearError = () => setError(null);

  return { error, handleError, clearError };
};

6.2 请求取消机制

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

const useCancelableRequest = () => {
  useEffect(() => {
    const source = axios.CancelToken.source();
    
    const fetchData = async () => {
      try {
        const response = await axios.get('/api/data', {
          cancelToken: source.token
        });
        // 处理数据
      } catch (error) {
        if (axios.isCancel(error)) {
          console.log('Request canceled:', error.message);
        } else {
          // 处理其他错误
        }
      }
    };

    fetchData();

    return () => {
      source.cancel('Component unmounted');
    };
  }, []);
};

6.3 性能优化技巧

  1. 请求去重:使用相同的key避免重复请求
  2. 数据分区:按业务模块划分查询key
  3. 预加载策略:在用户可能操作前预加载数据
  4. 分页优化:使用无限滚动或虚拟列表

七、实战案例:电商平台数据层设计

7.1 项目结构规划

src/
  ├── api/           # API接口定义
  ├── hooks/         # 自定义请求hook
  ├── types/         # TypeScript类型定义
  └── utils/         # 工具函数

7.2 领域模型设计

// types/product.ts
export interface Product {
  id: string;
  name: string;
  price: number;
  description: string;
  category: string;
  images: string[];
}

export interface ProductListParams {
  page?: number;
  limit?: number;
  category?: string;
  sortBy?: string;
}

7.3 API层抽象

// api/product.ts
import { request } from '@/utils/request';

export const productApi = {
  getProducts: (params: ProductListParams) => 
    request.get<Product[]>('/products', { params }),
  
  getProduct: (id: string) => 
    request.get<Product>(`/products/${id}`),
  
  createProduct: (data: Partial<Product>) => 
    request.post<Product>('/products', data),
  
  updateProduct: (id: string, data: Partial<Product>) => 
    request.put<Product>(`/products/${id}`, data),
  
  deleteProduct: (id: string) => 
    request.delete(`/products/${id}`),
};

7.4 自定义Hook封装

// hooks/useProducts.ts
import { useQuery } from 'umi';
import { productApi } from '@/api/product';
import { Product, ProductListParams } from '@/types/product';

export const useProducts = (params: ProductListParams = {}) => {
  return useQuery(
    ['products', params],
    () => productApi.getProducts(params),
    {
      staleTime: 5 * 60 * 1000,
      keepPreviousData: true,
    }
  );
};

export const useProduct = (id: string) => {
  return useQuery(
    ['product', id],
    () => productApi.getProduct(id),
    {
      enabled: !!id, // 只有id存在时才发起请求
    }
  );
};

总结

umi框架为React应用提供了灵活多样的数据请求解决方案。选择合适的技术栈需要综合考虑项目需求、团队经验和性能要求:

  • 简单场景:优先选择axios,学习成本低且灵活
  • 中等复杂度:SWR提供了良好的开箱即用体验
  • 企业级应用:React Query的完整功能栈更适合复杂业务

无论选择哪种方案,都要注意错误处理的统一性、性能优化的系统性以及代码的可维护性。良好的数据层设计是前端应用稳定性的基石,也是开发效率的重要保障。

通过本文的详细讲解和实战案例,相信你已经掌握了在umi项目中集成和使用主流数据请求方案的完整知识体系。在实际项目中,根据具体需求选择最适合的方案,并遵循最佳实践,才能构建出高性能、可维护的前端应用。

【免费下载链接】umi A framework in react community ✨ 【免费下载链接】umi 项目地址: https://gitcode.com/GitHub_Trending/um/umi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值