refine
Refine React meta-framework 開發專家。精通 CRUD-heavy 應用程式架構、Data/Auth/Router Provider 系統、Ant Design UI 整合、REST Data Provider (@refinedev/rest)。當使用者需要建立 Refine 應用程式、實作 Provider、整合 Ant Design 元件、配置路由或資料層時,請啟用此技能。
Best use case
refine is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Refine React meta-framework 開發專家。精通 CRUD-heavy 應用程式架構、Data/Auth/Router Provider 系統、Ant Design UI 整合、REST Data Provider (@refinedev/rest)。當使用者需要建立 Refine 應用程式、實作 Provider、整合 Ant Design 元件、配置路由或資料層時,請啟用此技能。
Teams using refine should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/refine/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How refine Compares
| Feature / Agent | refine | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Refine React meta-framework 開發專家。精通 CRUD-heavy 應用程式架構、Data/Auth/Router Provider 系統、Ant Design UI 整合、REST Data Provider (@refinedev/rest)。當使用者需要建立 Refine 應用程式、實作 Provider、整合 Ant Design 元件、配置路由或資料層時,請啟用此技能。
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Refine — React CRUD Meta-Framework 開發指南
## 核心概念
Refine 是一個針對 **CRUD-heavy** 網頁應用程式優化的 React meta-framework,採用 **headless 架構**,商業邏輯與 UI 完全解耦。
### 三大支柱
1. **Provider 系統** — 可替換的服務層(Data、Auth、Router、Notification、i18n、Access Control)
2. **Resource 概念** — 將 API endpoint 映射至 CRUD 路由的核心抽象
3. **Hooks 架構** — 基於 TanStack Query 的 headless data hooks
---
## 安裝與基本設定
```bash
npm create refine-app@latest
# 或手動安裝
npm i @refinedev/core @refinedev/react-router @refinedev/antd antd
npm i @refinedev/rest # REST Data Provider
```
### 最小化 App.tsx
```tsx
import { Refine } from "@refinedev/core";
import { BrowserRouter, Route, Routes } from "react-router";
import routerProvider from "@refinedev/react-router";
import dataProvider from "@refinedev/simple-rest";
export default function App() {
return (
<BrowserRouter>
<Refine
routerProvider={routerProvider}
dataProvider={dataProvider("https://api.example.com")}
resources={[
{
name: "products",
list: "/products",
show: "/products/:id",
edit: "/products/:id/edit",
create: "/products/new",
},
]}
>
<Routes>
<Route path="/products" element={<ProductList />} />
</Routes>
</Refine>
</BrowserRouter>
);
}
```
> 完整 App 範例見 [references/app-setup.md](./references/app-setup.md)
---
## `<Refine>` Component 屬性
| 屬性 | 類型 | 說明 |
|------|------|------|
| `dataProvider` | `DataProvider \| Record<string, DataProvider>` | 必要。單一或多個 data provider |
| `routerProvider` | `RouterProvider` | 路由整合 |
| `authProvider` | `AuthProvider` | 認證/授權 |
| `notificationProvider` | `NotificationProvider` | 通知系統 |
| `i18nProvider` | `I18nProvider` | 國際化 |
| `accessControlProvider` | `AccessControlProvider` | 存取控制 |
| `resources` | `ResourceProps[]` | 資源定義清單 |
| `options` | `RefineOptions` | 全域設定(mutationMode、syncWithLocation 等)|
### Resource 定義
```tsx
resources={[
{
name: "products", // API resource 名稱(傳給 data provider)
identifier: "my-products", // 可選,用於 UI 匹配(不影響 API 呼叫)
list: "/products",
show: "/products/:id",
edit: "/products/:id/edit",
create: "/products/new",
meta: {
label: "產品管理", // 選單顯示名稱
icon: <ShopOutlined />,
canDelete: true,
},
},
]}
```
---
## Data Provider 介面
Data Provider 是 Refine 與後端通訊的橋樑,需實作以下方法:
### 必要方法
```typescript
interface DataProvider {
getList: (params: {
resource: string;
pagination?: { current?: number; pageSize?: number; mode?: "off" | "client" | "server" };
sorters?: CrudSorters;
filters?: CrudFilters;
meta?: MetaQuery;
}) => Promise<{ data: BaseRecord[]; total: number }>;
getOne: (params: {
resource: string;
id: BaseKey;
meta?: MetaQuery;
}) => Promise<{ data: BaseRecord }>;
create: (params: {
resource: string;
variables: Record<string, unknown>;
meta?: MetaQuery;
}) => Promise<{ data: BaseRecord }>;
update: (params: {
resource: string;
id: BaseKey;
variables: Record<string, unknown>;
meta?: MetaQuery;
}) => Promise<{ data: BaseRecord }>;
deleteOne: (params: {
resource: string;
id: BaseKey;
variables?: Record<string, unknown>;
meta?: MetaQuery;
}) => Promise<{ data: BaseRecord }>;
getApiUrl: () => string;
}
```
### 選用方法
```typescript
getMany?: (params: { resource: string; ids: BaseKey[]; meta?: MetaQuery }) => Promise<{ data: BaseRecord[] }>;
createMany?: (params: { resource: string; variables: Record<string, unknown>[]; meta?: MetaQuery }) => Promise<{ data: BaseRecord[] }>;
updateMany?: (...) => Promise<...>;
deleteMany?: (...) => Promise<...>;
custom?: (params: { url: string; method: string; payload?: unknown; headers?: object; meta?: MetaQuery }) => Promise<{ data: unknown }>;
```
> 完整 custom Data Provider 範例見 [references/data-provider.md](./references/data-provider.md)
---
## @refinedev/rest(REST Data Provider)
新版 REST Data Provider,基於 KY HTTP client。
```bash
npm i @refinedev/rest
```
```typescript
import { createDataProvider } from "@refinedev/rest";
const { dataProvider, kyInstance } = createDataProvider(
"https://api.example.com/v1",
{
// 可選:自訂每個方法的行為
getList: {
buildQueryParams: ({ pagination, sorters, filters }) => {
return {
_page: pagination?.current,
_limit: pagination?.pageSize,
_sort: sorters?.[0]?.field,
_order: sorters?.[0]?.order,
...filters?.reduce((acc, filter) => {
if ("field" in filter) acc[filter.field] = filter.value;
return acc;
}, {}),
};
},
getTotalCount: ({ response }) => {
return Number(response.headers.get("x-total-count"));
},
},
}
);
```
> 完整範例見 [references/rest-data-provider.md](./references/rest-data-provider.md)
---
## Auth Provider 介面
```typescript
interface AuthProvider {
login: (params: { email?: string; username?: string; password?: string; [key: string]: unknown }) => Promise<AuthActionResponse>;
check: (params?: unknown) => Promise<CheckResponse>;
logout: (params?: unknown) => Promise<AuthActionResponse>;
onError: (error: unknown) => Promise<OnErrorResponse>;
// 選用
register?: (params: unknown) => Promise<AuthActionResponse>;
forgotPassword?: (params: unknown) => Promise<AuthActionResponse>;
updatePassword?: (params: unknown) => Promise<AuthActionResponse>;
getPermissions?: (params?: unknown) => Promise<unknown>;
getIdentity?: (params?: unknown) => Promise<unknown>;
}
// 回傳類型
type AuthActionResponse = {
success: boolean;
redirectTo?: string;
error?: { message: string; name: string };
};
type CheckResponse = {
authenticated: boolean;
redirectTo?: string; // 未認證時重導向
logout?: boolean; // 是否登出
error?: Error;
};
```
### 使用 Hooks
```typescript
import { useLogin, useLogout, useIsAuthenticated, useGetIdentity } from "@refinedev/core";
const { mutate: login } = useLogin();
const { mutate: logout } = useLogout();
const { data: authData } = useIsAuthenticated();
const { data: identity } = useGetIdentity<{ name: string; email: string }>();
```
---
## Data Hooks
### useList
```typescript
import { useList } from "@refinedev/core";
const { data, isLoading, isError } = useList({
resource: "products",
pagination: { current: 1, pageSize: 20, mode: "server" },
sorters: [{ field: "id", order: "desc" }],
filters: [
{ field: "category", operator: "eq", value: "electronics" },
{ field: "price", operator: "lte", value: 1000 },
],
meta: { headers: { "x-custom-header": "value" } },
});
// data.data: BaseRecord[]
// data.total: number
```
### useOne
```typescript
const { data, isLoading } = useOne({ resource: "products", id: 1 });
```
### useCreate
```typescript
const { mutate, isLoading } = useCreate();
mutate({
resource: "products",
values: { name: "新產品", price: 100 },
});
```
### useUpdate
```typescript
const { mutate } = useUpdate();
mutate({
resource: "products",
id: 1,
values: { price: 200 },
mutationMode: "optimistic", // "pessimistic" | "optimistic" | "undoable"
});
```
### useDelete
```typescript
const { mutate: deleteProduct } = useDelete();
deleteProduct({ resource: "products", id: 1 });
```
### useTable(@refinedev/core)
```typescript
import { useTable } from "@refinedev/core";
const { tableQuery, current, setCurrent, pageSize, setPageSize,
sorters, setSorters, filters, setFilters } = useTable({
resource: "products",
syncWithLocation: true, // 同步 URL query string
});
```
### Filter Operators
| operator | 說明 |
|----------|------|
| `eq` | 等於 |
| `ne` | 不等於 |
| `lt` / `gt` | 小於 / 大於 |
| `lte` / `gte` | 小於等於 / 大於等於 |
| `contains` | 包含(字串) |
| `startswith` / `endswith` | 開頭 / 結尾 |
| `in` / `nin` | 在清單內 / 不在清單內 |
| `between` | 範圍 |
| `null` / `nnull` | 為空 / 不為空 |
---
## Ant Design UI 整合(@refinedev/antd)
```bash
npm i @refinedev/antd antd
```
### 必要設定
```tsx
import "@refinedev/antd/dist/reset.css"; // 必須匯入
import { App as AntdApp, ConfigProvider } from "antd";
import { RefineThemes, useNotificationProvider } from "@refinedev/antd";
<ConfigProvider theme={RefineThemes.Blue}>
<AntdApp>
<Refine notificationProvider={useNotificationProvider}>
{/* ... */}
</Refine>
</AntdApp>
</ConfigProvider>
```
### ThemedLayout
```tsx
import { ThemedLayout } from "@refinedev/antd";
<Route element={<ThemedLayout />}>
<Route path="/products" element={<ProductList />} />
</Route>
```
### CRUD 頁面元件
| 元件 | 用途 |
|------|------|
| `<List>` | 列表頁容器,自動加入建立按鈕 |
| `<Show>` | 顯示頁容器,含編輯/刪除按鈕 |
| `<Edit>` | 編輯頁容器,含儲存按鈕 |
| `<Create>` | 建立頁容器,含儲存按鈕 |
### useTable(@refinedev/antd)
```tsx
import { useTable, List, getDefaultSortOrder, getDefaultFilter, FilterDropdown } from "@refinedev/antd";
import { Table } from "antd";
export const ProductList = () => {
const { tableProps, sorters, filters } = useTable<IProduct>({
syncWithLocation: true,
sorters: { initial: [{ field: "id", order: "desc" }] },
filters: { initial: [{ field: "status", operator: "eq", value: "active" }] },
onSearch: (values: { name: string }) => [
{ field: "name", operator: "contains", value: values.name },
],
});
return (
<List>
<Table {...tableProps} rowKey="id">
<Table.Column
dataIndex="name"
title="名稱"
sorter
defaultSortOrder={getDefaultSortOrder("name", sorters)}
/>
<Table.Column
dataIndex="status"
title="狀態"
defaultFilteredValue={getDefaultFilter("status", filters)}
filterDropdown={(props) => (
<FilterDropdown {...props}>
<Select options={[{ label: "啟用", value: "active" }]} />
</FilterDropdown>
)}
/>
</Table>
</List>
);
};
```
### useForm(@refinedev/antd)
```tsx
import { Edit, useForm } from "@refinedev/antd";
import { Form, Input } from "antd";
export const ProductEdit = () => {
const { formProps, saveButtonProps } = useForm<IProduct>({
action: "edit", // "create" | "edit" | "clone"
redirect: "show", // 提交後跳轉
onMutationSuccess: (data) => {
console.log("成功:", data);
},
});
return (
<Edit saveButtonProps={saveButtonProps}>
<Form {...formProps} layout="vertical">
<Form.Item label="名稱" name="name" rules={[{ required: true }]}>
<Input />
</Form.Item>
</Form>
</Edit>
);
};
```
### 欄位顯示元件
```tsx
import { TextField, NumberField, DateField, MarkdownField, BooleanField, TagField, UrlField, EmailField, ImageField } from "@refinedev/antd";
<TextField value="文字" />
<NumberField value={1234.56} options={{ style: "currency", currency: "TWD" }} />
<DateField value="2024-01-01" format="YYYY/MM/DD" />
<BooleanField value={true} />
<TagField value="published" />
```
### 操作按鈕元件
```tsx
import { ShowButton, EditButton, DeleteButton, CreateButton, ListButton, SaveButton, RefreshButton, CloneButton } from "@refinedev/antd";
// 在 Table 中使用
<Table.Column
title="操作"
render={(_, record) => (
<Space>
<ShowButton recordItemId={record.id} hideText size="small" />
<EditButton recordItemId={record.id} hideText size="small" />
<DeleteButton recordItemId={record.id} hideText size="small" />
</Space>
)}
/>
```
> 完整 CRUD 頁面範例見 [references/antd-crud.md](./references/antd-crud.md)
---
## Router Provider
```typescript
// React Router v7
import routerProvider from "@refinedev/react-router";
// Next.js
import routerProvider from "@refinedev/nextjs-router";
```
### 路由 Hooks
```typescript
import { useGo, useBack, useParsed, useNavigation } from "@refinedev/core";
const go = useGo();
go({ to: { resource: "products", action: "list" } });
go({ to: "/custom-page", type: "push" });
const { resource, action, id, params } = useParsed();
const { list, show, edit, create } = useNavigation();
list("products");
show("products", 1);
```
---
## Notification Provider
```tsx
import { useNotificationProvider } from "@refinedev/antd";
<Refine notificationProvider={useNotificationProvider}>
{/* 會自動顯示 CRUD 操作的成功/失敗通知 */}
</Refine>
```
### 手動觸發通知
```typescript
import { useNotification } from "@refinedev/core";
const { open, close } = useNotification();
open({
type: "success", // "success" | "error" | "progress"
message: "操作成功",
description: "資料已儲存",
key: "unique-key", // 用於 close
});
close("unique-key");
```
---
## Access Control Provider
```typescript
import { useCan, CanAccess } from "@refinedev/core";
// Hook 方式
const { data: { can } } = useCan({
resource: "products",
action: "delete",
params: { id: 1 },
});
// Component 方式
<CanAccess resource="products" action="create" fallback={<span>無權限</span>}>
<CreateButton />
</CanAccess>
```
---
## i18n Provider
```typescript
import { I18nProvider } from "@refinedev/core";
import i18n from "i18next";
const i18nProvider: I18nProvider = {
translate: (key: string, options?: object) => i18n.t(key, options),
changeLocale: (lang: string) => i18n.changeLanguage(lang),
getLocale: () => i18n.language,
};
// 必要的翻譯 key 結構:
// pages.login, pages.register, pages.error
// actions.create, actions.edit, actions.delete, actions.show
// buttons.save, buttons.cancel, buttons.confirm
// notifications.createSuccess, notifications.createError
```
---
## 進階設定
### Mutation Mode
```tsx
<Refine
options={{
mutationMode: "optimistic", // "pessimistic" | "optimistic" | "undoable"
syncWithLocation: true, // URL 與 table 狀態同步
warnWhenUnsavedChanges: true,
}}
>
```
### 多個 Data Provider
```tsx
<Refine
dataProvider={{
default: restDataProvider("https://api.example.com"),
cms: strapiDataProvider("https://cms.example.com"),
}}
>
```
```typescript
useList({ resource: "posts", dataProviderName: "cms" });
```
### Meta 傳遞
```typescript
// 傳遞自訂參數到 data provider
useList({
resource: "products",
meta: {
headers: { Authorization: `Bearer ${token}` },
queryContext: { tenant: "acme" },
},
});
```
---
## 最佳實踐
1. **Resource 命名** — 使用複數小寫(`products`、`blog-posts`),對應 API path
2. **Provider 抽象** — 不要在元件內直接 fetch,透過 hooks 使用 data provider
3. **Type Safety** — 為每個 resource 定義 interface,傳給 hooks 泛型
4. **Error Handling** — Auth Provider 的 `onError` 處理 401/403 自動登出
5. **Optimistic Updates** — CRUD-heavy 應用建議使用 `mutationMode: "optimistic"`
6. **URL Sync** — 在列表頁啟用 `syncWithLocation: true` 確保狀態可分享
7. **Meta 使用** — 透過 `meta` 傳遞 headers、tenant ID 等上下文資訊
---
## 套件速查
| 套件 | 用途 |
|------|------|
| `@refinedev/core` | 核心 hooks 和 providers |
| `@refinedev/react-router` | React Router v7 整合 |
| `@refinedev/nextjs-router` | Next.js 整合 |
| `@refinedev/antd` | Ant Design UI 整合 |
| `@refinedev/mui` | Material UI 整合 |
| `@refinedev/simple-rest` | 簡易 REST data provider |
| `@refinedev/rest` | 進階 REST data provider(KY-based)|
| `@refinedev/strapi-v4` | Strapi v4 data provider |
| `@refinedev/supabase` | Supabase data provider |Related Skills
wpds
Use when building UIs leveraging the WordPress Design System (WPDS) and its components, tokens, patterns, etc.
wp-wpcli-and-ops
Use when working with WP-CLI (wp) for WordPress operations: safe search-replace, db export/import, plugin/theme/user/content management, cron, cache flushing, multisite, and scripting/automation with wp-cli.yml.
wp-rest-api
Use when building, extending, or debugging WordPress REST API endpoints/routes: register_rest_route, WP_REST_Controller/controller classes, schema/argument validation, permission_callback/authentication, response shaping, register_rest_field/register_meta, or exposing CPTs/taxonomies via show_in_rest.
wp-project-triage
Use when you need a deterministic inspection of a WordPress repository (plugin/theme/block theme/WP core/Gutenberg/full site) including tooling/tests/version hints, and a structured JSON report to guide workflows and guardrails.
wp-plugin-development
Use when developing WordPress plugins: architecture and hooks, activation/deactivation/uninstall, admin UI and Settings API, data storage, cron/tasks, security (nonces/capabilities/sanitization/escaping), and release packaging.
wp-playground
Use for WordPress Playground workflows: fast disposable WP instances in the browser or locally via @wp-playground/cli (server, run-blueprint, build-snapshot), auto-mounting plugins/themes, switching WP/PHP versions, blueprints, and debugging (Xdebug).
wp-phpstan
Use when configuring, running, or fixing PHPStan static analysis in WordPress projects (plugins/themes/sites): phpstan.neon setup, baselines, WordPress-specific typing, and handling third-party plugin classes.
wp-performance
Use when investigating or improving WordPress performance (backend-only agent): profiling and measurement (WP-CLI profile/doctor, Server-Timing, Query Monitor via REST headers), database/query optimization, autoloaded options, object caching, cron, HTTP API calls, and safe verification.
wp-interactivity-api
Use when building or debugging WordPress Interactivity API features (data-wp-* directives, @wordpress/interactivity store/state/actions, block viewScriptModule integration, wp_interactivity_*()) including performance, hydration, and directive behavior.
wp-block-themes
Use when developing WordPress block themes: theme.json (global settings/styles), templates and template parts, patterns, style variations, and Site Editor troubleshooting (style hierarchy, overrides, caching).
wp-block-development
Use when developing WordPress (Gutenberg) blocks: block.json metadata, register_block_type(_from_metadata), attributes/serialization, supports, dynamic rendering (render.php/render_callback), deprecations/migrations, viewScript vs viewScriptModule, and @wordpress/scripts/@wordpress/create-block build and test workflows.
wp-abilities-api
Use when working with the WordPress Abilities API (wp_register_ability, wp_register_ability_category, /wp-json/wp-abilities/v1/*, @wordpress/abilities) including defining abilities, categories, meta, REST exposure, and permissions checks for clients.