Refine项目教程:从零开始创建自定义Data Provider

Refine项目教程:从零开始创建自定义Data Provider

refine 一个用于构建内部工具、管理面板、仪表盘和B2B应用程序的React框架,具有无与伦比的灵活性。 refine 项目地址: https://gitcode.com/gh_mirrors/re/refine

前言

在现代前端开发中,与后端API的交互是不可避免的。Refine作为一个强大的React框架,提供了Data Provider这一抽象层来简化API交互。本文将深入讲解如何为Refine项目创建自定义Data Provider,帮助开发者理解其核心机制并实现符合自身业务需求的API适配器。

什么是Data Provider?

Data Provider是Refine框架中负责与后端API通信的适配器层。它定义了标准化的方法来实现CRUD(创建、读取、更新、删除)操作,使得前端组件可以以统一的方式与各种不同类型的API交互。

为什么需要自定义Data Provider?

虽然Refine提供了内置的Data Provider实现,但在实际项目中,我们经常会遇到:

  1. 非标准REST API接口
  2. 特殊的认证机制
  3. 自定义的错误处理需求
  4. 独特的业务逻辑要求

这些情况下,我们就需要创建自定义的Data Provider。

准备工作

安装必要依赖

首先需要安装axios和query-string这两个库:

npm install axios query-string@7
  • axios:强大的HTTP客户端,支持请求/响应拦截器
  • query-string:用于处理URL查询参数的序列化

基础结构搭建

创建src/data-provider.ts文件,定义基本结构:

import { DataProvider } from "@refinedev/core";
import { stringify } from "query-string";

export const dataProvider = (apiUrl: string): DataProvider => ({
  // 方法将在这里实现
});

错误处理机制

良好的错误处理是健壮应用的基础。我们可以利用axios的拦截器实现统一的错误处理:

import axios from "axios";
import { DataProvider, HttpError } from "@refinedev/core";

const axiosInstance = axios.create();

axiosInstance.interceptors.response.use(
  (response) => response,
  (error) => {
    const customError: HttpError = {
      ...error,
      message: error.response?.data?.message,
      statusCode: error.response?.status,
    };
    return Promise.reject(customError);
  }
);

这种处理方式可以:

  1. 统一错误格式
  2. 提取有意义的错误信息
  3. 方便前端组件处理

核心方法实现

1. getList - 获取资源列表

getList方法用于获取分页、排序和过滤后的资源列表。

基础实现
getList: async ({ resource }) => {
  const url = `${apiUrl}/${resource}`;
  const { data, headers } = await axiosInstance.get(url);
  return {
    data,
    total: +headers["x-total-count"],
  };
}
添加分页支持
getList: async ({ resource, pagination }) => {
  const { current = 1, pageSize = 10 } = pagination ?? {};
  const query = {
    _start: (current - 1) * pageSize,
    _end: current * pageSize,
  };
  // ...其余代码
}
添加排序支持
if (sorters?.length) {
  query._sort = sorters[0].field;
  query._order = sorters[0].order;
}
添加过滤支持

首先定义操作符映射函数:

const mapOperator = (operator: CrudOperators): string => {
  switch (operator) {
    case "ne": return "_ne";
    case "gte": return "_gte";
    case "lte": return "_lte";
    case "contains": return "_like";
    default: return "";
  }
};

然后实现过滤生成器:

const generateFilters = (filters?: CrudFilters) => {
  const queryFilters: Record<string, string> = {};
  filters?.forEach((filter) => {
    if ("field" in filter) {
      queryFilters[`${filter.field}${mapOperator(filter.operator)}`] = filter.value;
    }
  });
  return queryFilters;
};

2. create - 创建资源

create: async ({ resource, variables }) => {
  const url = `${apiUrl}/${resource}`;
  const { data } = await axiosInstance.post(url, variables);
  return { data };
}

3. update - 更新资源

update: async ({ resource, id, variables }) => {
  const url = `${apiUrl}/${resource}/${id}`;
  const { data } = await axiosInstance.patch(url, variables);
  return { data };
}

4. deleteOne - 删除资源

deleteOne: async ({ resource, id, variables }) => {
  const url = `${apiUrl}/${resource}/${id}`;
  const { data } = await axiosInstance.delete(url, { data: variables });
  return { data };
}

5. getOne - 获取单个资源

getOne: async ({ resource, id }) => {
  const url = `${apiUrl}/${resource}/${id}`;
  const { data } = await axiosInstance.get(url);
  return { data };
}

6. getApiUrl - 获取API基础URL

getApiUrl: () => apiUrl

7. custom - 自定义请求

custom: async ({ url, method, filters, sorters, payload, query }) => {
  let requestUrl = `${url}?`;
  
  // 处理排序
  if (sorters?.length) {
    requestUrl += `&${stringify({
      _sort: sorters[0].field,
      _order: sorters[0].order,
    })}`;
  }
  
  // 处理过滤
  if (filters) {
    requestUrl += `&${stringify(generateFilters(filters))}`;
  }
  
  // 处理额外查询参数
  if (query) {
    requestUrl += `&${stringify(query)}`;
  }
  
  // 根据方法类型发送请求
  let axiosResponse;
  switch (method) {
    case "put":
    case "post":
    case "patch":
      axiosResponse = await axiosInstance[method](url, payload);
      break;
    case "delete":
      axiosResponse = await axiosInstance.delete(url, { data: payload });
      break;
    default:
      axiosResponse = await axiosInstance.get(requestUrl);
  }
  
  return { data: axiosResponse.data };
}

使用方法

完成Data Provider后,可以在Refine配置中使用:

import { dataProvider } from "./data-provider";

const App = () => (
  <Refine
    dataProvider={dataProvider("https://api.example.com")}
    /* 其他配置 */
  />
);

在组件中使用示例:

const { data } = useList({
  resource: "posts",
  filters: [
    { field: "status", operator: "eq", value: "published" }
  ],
  sorters: [
    { field: "createdAt", order: "desc" }
  ],
  pagination: { current: 1, pageSize: 10 }
});

总结

通过本文,我们详细讲解了如何为Refine项目创建自定义Data Provider。关键点包括:

  1. 基础结构搭建
  2. 统一的错误处理机制
  3. 完整的CRUD方法实现
  4. 分页、排序和过滤的支持
  5. 自定义请求处理

自定义Data Provider可以完美适配各种API设计,为前端开发提供统一的接口,大大提升开发效率和代码可维护性。

refine 一个用于构建内部工具、管理面板、仪表盘和B2B应用程序的React框架,具有无与伦比的灵活性。 refine 项目地址: https://gitcode.com/gh_mirrors/re/refine

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

曹艺程Luminous

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

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

抵扣说明:

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

余额充值