重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
react-admin by marmelab/react-admin
npx skills add https://github.com/marmelab/react-admin --skill react-adminReact-admin 是一个基于 REST/GraphQL API 构建单页面应用的框架。它构建在 React Query、react-hook-form、react-router 和 Material UI 之上。它提供了 150 多个组件和数十个钩子。在编写自定义代码之前,请务必检查 react-admin 是否已经为任务提供了组件或钩子。完整文档:https://marmelab.com/react-admin/doc/
React-admin 从不直接调用 API。所有通信都通过提供者进行——这些适配器将 react-admin 的标准调用转换为特定于 API 的请求。三个主要的提供者是:
getList、getOne、create、update、delete、getMany、getManyReference、updateMany、)。参见 和 。广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
deleteManytranslate、changeLocale、getLocale)。关键规则:切勿在组件中使用 fetch、axios 或直接进行 HTTP 调用。始终使用数据提供者钩子。这确保了适当的缓存、加载状态、错误处理、身份验证和乐观渲染。
React-admin 使用组合而非配置。通过传递子组件来覆盖行为,而不是设置数十个属性:
<Edit actions={<MyCustomActions />}>
<SimpleForm>
<TextInput source="title" />
</SimpleForm>
</Edit>
要自定义布局,请将自定义布局组件传递给 <Admin layout={MyLayout}>。要自定义菜单,请将其传递给 <Layout menu={MyMenu}>。这种链式设计是有意为之的——参见 Architecture。
React-admin 组件通过 React 上下文向子组件暴露数据。使用钩子访问数据,而不是向下传递属性:
useRecordContext() —— Show/Edit/Create 视图中的当前记录。参见 useRecordContext。useListContext() —— List 视图中的列表数据、过滤器、分页、排序。参见 useListContext。useShowContext()、useEditContext()、useCreateContext() —— 详情页面的页面级状态。useTranslate() —— 来自 i18nProvider 的翻译函数。useGetIdentity() —— 来自 authProvider 的当前用户。当 react-admin 组件的 UI 不符合要求时,使用底层钩子而不是从头开始构建。控制器钩子(名为 use*Controller)提供了所有逻辑,但没有 UI:
useListController() —— 列表获取、过滤、分页逻辑useEditController() —— 编辑表单获取和提交逻辑useShowController() —— 展示页面数据获取逻辑<Resource> 自动声明 CRUD 路由(/posts、/posts/create、/posts/:id/edit、/posts/:id/show)。使用 <CustomRoutes> 处理非 CRUD 页面。使用 useCreatePath() 构建资源 URL,并使用来自 react-admin 的 <Link> 进行导航。默认路由器是 react-router (HashRouter),但也通过 routerProvider 支持 TanStack Router。参见 Routing。
const { data, total, isPending, error } = useGetList('posts', {
pagination: { page: 1, perPage: 25 },
sort: { field: 'created_at', order: 'DESC' },
filter: { status: 'published' },
});
const { data: record, isPending } = useGetOne('posts', { id: 123 });
const { data: records } = useGetMany('posts', { ids: [1, 2, 3] });
const { data, total } = useGetManyReference('comments', {
target: 'post_id', id: 123,
pagination: { page: 1, perPage: 25 },
});
参见 useGetList、useGetOne。
所有变更都返回 [mutate, state]。它们支持三种变更模式:
pessimistic(默认):等待服务器响应,然后更新 UI。
optimistic:立即更新 UI,服务器错误时回滚。
undoable:更新 UI,显示撤销通知,延迟后提交。
const [create, { isPending }] = useCreate(); const [update] = useUpdate(); const [deleteOne] = useDelete();
// 使用资源和参数调用 create('posts', { data: { title: 'Hello' } }); update('posts', { id: 1, data: { title: 'Updated' }, previousData: record }); deleteOne('posts', { id: 1, previousData: record });
const authProvider = {
login: ({ username, password }) => Promise<void>,
logout: () => Promise<void>,
checkAuth: () => Promise<void>, // 验证凭据是否有效
checkError: (error) => Promise<void>, // 从 API 响应中检测身份验证错误
getIdentity: () => Promise<{ id, fullName, avatar }>,
getPermissions: () => Promise<any>,
canAccess: ({ resource, action, record }) => Promise<boolean>, // RBAC
};
每个身份验证提供者方法都有一个对应的钩子(例如 useGetIdentity()、useCanAccess())。
<Authenticated> 包装它们或调用 useAuthenticated() 来要求登录。参见 Authenticated。authProvider.canAccess() 中集中处理授权,而不是在单个组件中。使用 useCanAccess() 检查权限。参见 useCanAccess 和 AuthRBAC。httpClient。为给定页面预先获取所有数据(包括关系)是一种反模式。相反,应使用引用字段和输入按需获取相关记录。
{/* 基于 company_id 显示当前记录所属的公司 */}
<ReferenceField source="company_id" reference="companies" />
{/* 显示相关记录列表(反向外键) */}
<ReferenceManyField reference="comments" target="post_id">
<DataTable>
<TextField source="body" />
<DateField source="created_at" />
</DataTable>
</ReferenceManyField>
{/* 显示多个引用的记录(ID 数组) */}
<ReferenceArrayField source="tag_ids" reference="tags">
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>
{/* 从另一个资源中选择(外键) */}
<ReferenceInput source="company_id" reference="companies" />
{/* 从另一个资源中进行多选(ID 数组) */}
<ReferenceArrayInput source="tag_ids" reference="tags" />
React-admin 表单构建在 react-hook-form 之上。使用 <SimpleForm> 处理单列布局,使用 <TabbedForm> 处理多标签页布局。参见 SimpleForm、TabbedForm。
将验证器传递给输入组件:required()、minLength(min)、maxLength(max)、minValue(min)、maxValue(max)、number()、email()、regex(pattern, message),或返回错误字符串的自定义函数。
<TextInput source="title" validate={[required(), minLength(3)]} />
使用 RHF 的 useWatch() 创建响应字段值的动态表单:
将资源组件封装在索引文件中,以便清晰导入:
// posts/index.ts
export default {
list: PostList,
create: PostCreate,
edit: PostEdit,
icon: PostIcon,
recordRepresentation: (record) => record.title, // 记录在引用中如何显示
};
使用特定领域的方法扩展 dataProvider:
const dataProvider = {
...baseDataProvider,
archivePost: async (id) => { /* 自定义逻辑 */ },
};
// 通过 useDataProvider 和 useQuery 调用:
// const dp = useDataProvider();
// const { data } = useQuery(['archivePost', id], () => dp.archivePost(id));
使用 useStore() 处理持久化的用户偏好(主题、列可见性、保存的过滤器):
const [theme, setTheme] = useStore('theme', 'light');
参见 Store。
const notify = useNotify();
const redirect = useRedirect();
const refresh = useRefresh();
notify('记录已保存', { type: 'success' });
redirect('list', 'posts'); // 导航到 /posts
redirect('edit', 'posts', 123); // 导航到 /posts/123
refresh(); // 使所有查询失效
<CanAccess> 和 useCanAccess每周安装量
71
代码仓库
GitHub 星标数
26.6K
首次出现
Feb 17, 2026
安全审计
安装于
codex69
kimi-cli69
gemini-cli69
github-copilot69
amp69
opencode69
React-admin is a framework for building single-page applications on top of REST/GraphQL APIs. It builds on top of React Query, react-hook-form, react-router, and Material UI. It provides 150+ components and dozens of hooks. Before writing custom code, always check if react-admin already provides a component or hook for the task. Full documentation: https://marmelab.com/react-admin/doc/
React-admin never calls APIs directly. All communication goes through providers — adapters that translate react-admin's standardized calls into API-specific requests. The three main providers are:
getList, getOne, create, update, delete, getMany, getManyReference, updateMany, deleteMany). See DataProviders and 50+ existing adapters.translate, changeLocale, getLocale).Critical rule : Never use fetch, axios, or direct HTTP calls in components. Always use data provider hooks. This ensures proper caching, loading states, error handling, authentication, and optimistic rendering.
React-admin uses composition over configuration. Override behavior by passing child components, not by setting dozens of props:
<Edit actions={<MyCustomActions />}>
<SimpleForm>
<TextInput source="title" />
</SimpleForm>
</Edit>
To customize the layout, pass a custom layout component to <Admin layout={MyLayout}>. To customize the menu, pass it to <Layout menu={MyMenu}>. This chaining is by design — see Architecture.
React-admin components expose data to descendants via React contexts. Access data using hooks rather than passing props down:
useRecordContext() — current record in Show/Edit/Create views. See useRecordContext.useListContext() — list data, filters, pagination, sort in List views. See useListContext.useShowContext(), useEditContext(), useCreateContext() — page-level state for detail views.useTranslate() — translation function from i18nProvider.useGetIdentity() — current user from authProvider.When a react-admin component's UI doesn't fit, use the underlying hook instead of building from scratch. Controller hooks (named use*Controller) provide all the logic without the UI:
useListController() — list fetching, filtering, pagination logicuseEditController() — edit form fetching and submission logicuseShowController() — show page data fetching logic<Resource> declares CRUD routes automatically (/posts, /posts/create, /posts/:id/edit, /posts/:id/show). Use <CustomRoutes> for non-CRUD pages. Use useCreatePath() to build resource URLs and <Link> from react-admin for navigation. Default router is react-router (HashRouter), but TanStack Router is also supported via routerProvider. See Routing.
const { data, total, isPending, error } = useGetList('posts', {
pagination: { page: 1, perPage: 25 },
sort: { field: 'created_at', order: 'DESC' },
filter: { status: 'published' },
});
const { data: record, isPending } = useGetOne('posts', { id: 123 });
const { data: records } = useGetMany('posts', { ids: [1, 2, 3] });
const { data, total } = useGetManyReference('comments', {
target: 'post_id', id: 123,
pagination: { page: 1, perPage: 25 },
});
See useGetList, useGetOne.
All mutations return [mutate, state]. They support three mutation modes :
pessimistic (default): Wait for server response, then update UI.
optimistic : Update UI immediately, revert on server error.
undoable : Update UI, show undo notification, commit after delay.
const [create, { isPending }] = useCreate(); const [update] = useUpdate(); const [deleteOne] = useDelete();
// Call with resource and params create('posts', { data: { title: 'Hello' } }); update('posts', { id: 1, data: { title: 'Updated' }, previousData: record }); deleteOne('posts', { id: 1, previousData: record });
Pass mutationMode: 'optimistic' or 'undoable' for instant UI feedback. See useCreate, useUpdate.
const authProvider = {
login: ({ username, password }) => Promise<void>,
logout: () => Promise<void>,
checkAuth: () => Promise<void>, // Verify credentials are valid
checkError: (error) => Promise<void>, // Detect auth errors from API responses
getIdentity: () => Promise<{ id, fullName, avatar }>,
getPermissions: () => Promise<any>,
canAccess: ({ resource, action, record }) => Promise<boolean>, // RBAC
};
Each auth provider method has a corresponding hook (e.g. useGetIdentity(), useCanAccess()).
<Authenticated> or call useAuthenticated() to require login. See Authenticated.authProvider.canAccess(), not in individual components. Use useCanAccess() to check permissions. See useCanAccess and AuthRBAC.httpClient in data provider setup.Fetching all the data (including relationships) upfront for a given page is an anti-pattern. Instead, fetch related records on demand using reference fields and inputs.
{/* Show a the company of the current record based on its company_id */}
<ReferenceField source="company_id" reference="companies" />
{/* Show a list of related records (reverse FK) */}
<ReferenceManyField reference="comments" target="post_id">
<DataTable>
<TextField source="body" />
<DateField source="created_at" />
</DataTable>
</ReferenceManyField>
{/* Show multiple referenced records (array of IDs) */}
<ReferenceArrayField source="tag_ids" reference="tags">
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>
See ReferenceField, ReferenceManyField, ReferenceArrayField.
{/* Select from another resource (FK) */}
<ReferenceInput source="company_id" reference="companies" />
{/* Multi-select from another resource (array of IDs) */}
<ReferenceArrayInput source="tag_ids" reference="tags" />
See ReferenceInput, ReferenceArrayInput.
React-admin forms are built on react-hook-form. Use <SimpleForm> for single-column layouts and <TabbedForm> for multi-tab layouts. See SimpleForm, TabbedForm.
Pass validators to input components: required(), minLength(min), maxLength(max), minValue(min), maxValue(max), number(), email(), regex(pattern, message), or a custom function returning an error string.
<TextInput source="title" validate={[required(), minLength(3)]} />
Use RHF's useWatch() to create dynamic forms that react to field values:
Encapsulate resource components in index files for clean imports:
// posts/index.ts
export default {
list: PostList,
create: PostCreate,
edit: PostEdit,
icon: PostIcon,
recordRepresentation: (record) => record.title, // How records appear in references
};
See Resource, RecordRepresentation.
Extend the dataProvider with domain-specific methods:
const dataProvider = {
...baseDataProvider,
archivePost: async (id) => { /* custom logic */ },
};
// Call via useDataProvider and useQuery:
// const dp = useDataProvider();
// const { data } = useQuery(['archivePost', id], () => dp.archivePost(id));
Use useStore() for persistent user preferences (theme, column visibility, saved filters):
const [theme, setTheme] = useStore('theme', 'light');
See Store.
const notify = useNotify();
const redirect = useRedirect();
const refresh = useRefresh();
notify('Record saved', { type: 'success' });
redirect('list', 'posts'); // Navigate to /posts
redirect('edit', 'posts', 123); // Navigate to /posts/123
refresh(); // Invalidate all queries
<CanAccess> and useCanAccess for authorization checksWeekly Installs
71
Repository
GitHub Stars
26.6K
First Seen
Feb 17, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex69
kimi-cli69
gemini-cli69
github-copilot69
amp69
opencode69
React视图过渡API使用指南:实现原生浏览器动画与状态管理
6,600 周安装
better-auth 身份验证库:D1 适配器指南、OAuth 2.1 与安全功能详解
434 周安装
Paperclip AI 技能开发指南:心跳执行、API 集成与任务自动化
452 周安装
viem 集成指南:为 TypeScript/JavaScript 应用连接 EVM 区块链
442 周安装
PDF OCR文字识别工具 - 支持影印PDF和图片提取文字,本地RapidOCR与云端AI双引擎
438 周安装
Rust物联网开发指南:IoT领域约束、设计模式与Rust实现
438 周安装
Vitest 测试框架:Vite驱动的下一代JavaScript/TypeScript单元测试工具
442 周安装