12k
All articles

使用 React Admin 构建数据驱动的应用

解析 React Admin 架构:dataProvider 方法、CRUD 视图、认证,以及用于后端无关应用的可复用列表和编辑页面。

OpenReplay Team
OpenReplay Team
使用 React Admin 构建数据驱动的应用

如果你曾经从零开始构建过管理后台——手动连接表格、表单、分页和 API 调用——你就会知道在编写第一行业务逻辑之前需要多少样板代码。React Admin 通过提供一个结构化框架来解决这个问题,让你能够在任何 API 之上构建 CRUD 应用。本文将介绍它的工作原理,重点关注使其后端无关且真正可复用的架构。

核心要点

  • React Admin 是一个用于构建数据驱动管理后台的 React 框架,而不是 UI 模板。它通过 dataProvider 抽象将数据层与 UI 层分离。
  • dataProvider 围绕九个核心方法构建,这些方法使 React Admin 能够适配任何后端——REST、GraphQL、Supabase 或其他——使框架真正实现后端无关。
  • 列表和编辑视图是声明式的:你组合字段组件和输入组件,React Admin 会自动处理数据获取、分页、排序和关系解析。
  • 身份验证、基于角色的访问控制和实时更新通过独立的 provider 和可选扩展来处理,保持核心框架的专注性和模块化。

React Admin 到底是什么

React Admin 不是一个 UI 模板。它是一个专门为数据驱动的管理后台和内部工具构建的 React 框架。它提供了用于列表、创建、编辑和删除记录的组件,但真正的价值在于它如何将数据层与 UI 层分离。

React Admin v5 的核心基于 React Queryreact-hook-formreact-router。它默认使用 MUI,但并不局限于此——React Admin 支持无头(headless)使用,这意味着如果需要,你可以使用自己的组件库。

三个核心构建块:Admin、Resource 和 dataProvider

每个 React Admin 应用都从三个概念开始:

  • <Admin> — 将所有内容连接在一起的根组件
  • <Resource> — 将名称映射到一组 CRUD 视图和 API 端点
  • dataProvider — React Admin 与后端之间的适配器
import { Admin, Resource } from "react-admin"
import { dataProvider } from "./dataProvider"
import { MovieList } from "./MovieList"
import { MovieEdit } from "./MovieEdit"

const App = () => (
  <Admin dataProvider={dataProvider}>
    <Resource name="movies" list={MovieList} edit={MovieEdit} />
  </Admin>
)

当用户导航到电影列表时,React Admin 调用 dataProvider.getList("movies", params)。当他们编辑记录时,调用 dataProvider.update("movies", params)。UI 从不直接与你的 API 通信。

React Admin dataProvider 的工作原理

dataProvider 围绕九个核心方法构建:getListgetOnegetManygetManyReferencecreateupdateupdateManydeletedeleteMany。每个方法接收一个请求对象并返回一个 Promise,并且在需要时可以使用额外的方法扩展 provider。

const dataProvider = {
  getList: async (resource, params) => {
    const { page, perPage } = params.pagination
    const { field, order } = params.sort
    const url = `${apiUrl}/${resource}?page=${page}&perPage=${perPage}&sort=${field}&order=${order}`
    const { json, headers } = await httpClient(url, { signal: params.signal })
    return {
      data: json,
      total: parseInt(headers.get("content-range").split("/").pop(), 10),
    }
  },
  // ...其他方法
}

React Admin 不关心你的后端是 REST、GraphQL、Supabase 还是 IndexedDB。只要每条记录都有一致的 id 字段,并且你的 dataProvider 返回预期的数据结构,它就能工作。常见后端已有预构建的适配器——ra-data-simple-restra-data-graphql 等——所以你通常不需要从头编写。

处理身份验证

身份验证没有内置在 dataProvider 中。React Admin 使用独立的 authProvider 来处理登录、登出和权限检查。一个常见的模式是在登录后存储 token,并在发起请求时在 dataProvider 内读取它,但 React Admin 也支持与外部身份提供商集成。

const httpClient = (url, options = {}) => {
  options.user = {
    authenticated: true,
    token: localStorage.getItem("token"),
  }
  return fetchUtils.fetchJson(url, options)
}

构建列表和编辑视图

一旦你的 dataProvider 连接好,构建视图主要是声明式的。对于列表视图,React Admin 的 <Datagrid> 组件根据你组合的字段组件渲染列。需要注意的是,<Datagrid> 仍然被广泛使用,但较新版本也引入了 <DataTable> 作为更现代的替代方案。

import { List, Datagrid, TextField, DateField, ReferenceField } from "react-admin"

export const MovieList = () => (
  <List>
    <Datagrid rowClick="edit">
      <TextField source="title" />
      <DateField source="release" />
      <ReferenceField source="director_id" reference="directors">
        <TextField source="lastname" />
      </ReferenceField>
    </Datagrid>
  </List>
)

<ReferenceField> 会自动调用 dataProvider.getMany("directors", ...) 来解析相关记录——无需手动获取数据。

编辑表单遵循相同的模式,使用 <Edit><SimpleForm>:

import { Edit, SimpleForm, TextInput, DateInput } from "react-admin"

export const MovieEdit = () => (
  <Edit>
    <SimpleForm>
      <TextInput source="title" />
      <DateInput source="release" />
    </SimpleForm>
  </Edit>
)

当你需要自定义逻辑时

对于特定资源的行为——比如在删除父记录之前删除相关记录——React Admin 提供了 withLifecycleCallbacks:

import { withLifecycleCallbacks } from "react-admin"

export const dataProvider = withLifecycleCallbacks(baseDataProvider, [
  {
    resource: "movies",
    beforeDelete: async (params, dp) => {
      const { data: reviews } = await dp.getList("reviews", {
        filter: { movie_id: params.id },
        pagination: { page: 1, perPage: 1000 },
        sort: { field: "id", order: "DESC" },
      })
      await dp.deleteMany("reviews", { ids: reviews.map((r) => r.id) })
      return params
    },
  },
])

这使你的业务逻辑保持在数据层附近,而不会分散在各个组件中。

React Admin 开箱即用不提供的功能

在你决定使用之前,有几件事值得了解:

  • RBAC(细粒度的基于角色的访问控制)需要企业版模块;基本的权限检查通过 authProvider 处理
  • 实时更新需要兼容的实时数据 provider 和额外的设置
  • 文件上传需要自定义 dataProvider 逻辑来处理 multipart/form-data

React Admin 也兼容 Next.js 等框架(包括 Pages 和 App Router),并支持默认设置之外的替代路由解决方案。

总结

React Admin 的优势在于其 dataProvider 抽象。一旦你针对 API 实现了这些核心方法,你就能获得一个功能完整的 CRUD 管理后台,具有排序、过滤、分页和关系处理功能——而无需自己构建任何这些功能。如果有适合你后端的预构建适配器,就从它开始;如果没有,就编写一个自定义的;随着应用的增长,再逐步添加身份验证和生命周期回调。

常见问题

我可以在 GraphQL 后端使用 React Admin 吗?

可以。React Admin 在设计上是后端无关的。你可以使用官方的 ra-data-graphql 适配器,或编写一个自定义 dataProvider,将所需的方法映射到你的 GraphQL 查询和变更。只要每条记录包含一致的 id 字段,并且你的 provider 返回预期的响应结构,React Admin 就能正常工作,无论后端是什么。

React Admin 如何处理资源之间的关系?

React Admin 提供了引用组件,如 ReferenceField 和 ReferenceInput,它们通过你的 dataProvider 自动获取相关记录。例如,ReferenceField 调用 dataProvider.getMany 将外键解析为显示值。你在组件树中声明关系,React Admin 在后台处理数据获取和缓存。

React Admin 适合具有复杂权限的生产应用吗?

开源版本通过 authProvider 支持基本的身份验证和简单的权限检查。对于细粒度的基于角色的访问控制,例如根据角色隐藏字段或限制操作,你需要企业版 RBAC 模块。尽早评估你的权限需求,以决定免费版本是否满足你的需求。

我可以自定义默认 Material UI 主题之外的外观吗?

可以。React Admin 默认使用 MUI,但支持无头使用,这意味着你可以用自己的组件库替换整个 UI 层。你也可以自定义 MUI 主题、覆盖单个组件,或构建完全自定义的视图,同时仍然使用 React Admin 的 hooks 进行数据获取、表单处理和路由。

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.