Refine 教程 - React 数据密集型应用框架
项目概述
Refine是一个基于React的开源框架,专为构建数据密集型应用(如管理面板、CRM系统、内容管理系统等)而设计,提供了一套完整的工具和组件,简化了数据管理、认证、授权、路由等常见功能的实现。
- 项目链接:https://github.com/refinedev/refine
- 官方网站:https://refine.dev/
- GitHub Stars:17k+
核心概念
- 资源(Resources):应用中的主要数据实体,如用户、产品、订单等
- 数据提供者(Data Providers):负责与后端API或数据库交互的接口
- 认证提供者(Auth Providers):处理用户认证和授权的接口
- 路由提供者(Router Providers):处理应用路由的接口
- CRUD操作:创建、读取、更新、删除数据的基本操作
- 钩子(Hooks):React钩子,用于访问框架功能
- 组件:预构建的UI组件,如表格、表单、模态框等
- 布局(Layout):应用的整体布局结构
- 上下文(Context):框架提供的全局状态管理
- 国际化(i18n):多语言支持
核心功能
- 数据管理:内置CRUD操作支持,与多种后端API集成
- 认证与授权:内置用户认证和细粒度权限控制
- 路由管理:自动生成资源路由,支持自定义路由
- UI组件:丰富的预构建组件,如表格、表单、模态框等
- 响应式设计:自动适应不同屏幕尺寸
- 国际化:内置多语言支持
- 主题定制:支持深色模式和自定义主题
- 实时数据:支持WebSocket和SSE等实时数据更新
- 文件上传:内置文件上传功能
- 审计日志:记录用户操作和系统事件
安装与设置
基本安装
# 使用 Create Refine App 初始化项目
npm create refine-app@latest my-refine-app
# 或者使用 npm 安装
npm install @refinedev/core
# 安装常用依赖
npm install @refinedev/react-router-v6 @refinedev/mui @emotion/react @emotion/styled @mui/material
# 安装数据提供者
npm install @refinedev/simple-rest
# 或者其他数据提供者,如
# npm install @refinedev/supabase
# npm install @refinedev/firebase
# npm install @refinedev/graphql基本设置
// src/App.jsx
import { Refine } from '@refinedev/core';
import { SimpleRest } from '@refinedev/simple-rest';
import { BrowserRouter, Routes, Route, Outlet } from 'react-router-dom';
import { Layout } from '@refinedev/mui';
import { CssBaseline, ThemeProvider, createTheme } from '@mui/material';
// 创建主题
const theme = createTheme({
palette: {
mode: 'light',
},
});
// 配置数据提供者
const dataProvider = SimpleRest({
apiUrl: 'https://api.example.com',
});
// 配置认证提供者
const authProvider = {
login: async ({ username, password }) => {
// 实现登录逻辑
return {
success: true,
redirectTo: '/',
token: '...',
user: {
id: 1,
name: 'John Doe',
email: 'john@example.com',
},
};
},
logout: async () => {
// 实现登出逻辑
return {
success: true,
redirectTo: '/login',
};
},
check: async () => {
// 实现认证检查逻辑
return {
authenticated: true,
};
},
getPermissions: async () => {
// 实现权限获取逻辑
return ['admin'];
},
getIdentity: async () => {
// 实现用户信息获取逻辑
return {
id: 1,
name: 'John Doe',
email: 'john@example.com',
};
},
};
// 自定义路由
const App = () => {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Refine
dataProvider={dataProvider}
authProvider={authProvider}
routerProvider={{
router: BrowserRouter,
routes: (
<Routes>
<Route element={<Layout />}>
<Route path="/" element={<Outlet />}>
{/* 资源路由将自动生成 */}
</Route>
</Route>
<Route path="/login" element={<LoginPage />} />
</Routes>
),
}}
resources={[
{
name: 'users',
list: '/users',
create: '/users/create',
edit: '/users/edit/:id',
show: '/users/show/:id',
meta: {
label: 'Users',
},
},
{
name: 'products',
list: '/products',
create: '/products/create',
edit: '/products/edit/:id',
show: '/products/show/:id',
meta: {
label: 'Products',
},
},
]}
/>
</ThemeProvider>
);
};
export default App;基本使用
创建资源
// src/App.jsx
import { Refine } from '@refinedev/core';
const App = () => {
return (
<Refine
// ... 其他配置
resources={[
{
name: 'users',
list: '/users',
create: '/users/create',
edit: '/users/edit/:id',
show: '/users/show/:id',
meta: {
label: 'Users',
icon: <UsersIcon />,
},
},
{
name: 'products',
list: '/products',
create: '/products/create',
edit: '/products/edit/:id',
show: '/products/show/:id',
meta: {
label: 'Products',
icon: <ProductsIcon />,
},
},
]}
/>
);
};实现列表页面
// src/pages/users/list.jsx
import { List, Table, TableBody, TableCell, TableHead, TableRow, TextField, EditButton, ShowButton, DeleteButton } from '@refinedev/mui';
import { useTable, useFilters } from '@refinedev/core';
const UserList = () => {
const { tableQueryResult, searchFormProps, filters } = useTable({
refineCoreProps: {
pagination: {
pageSize: 10,
},
},
});
const { data, isLoading } = tableQueryResult;
return (
<List
filters={
<TextField
{...searchFormProps}
placeholder="Search users"
style={{ width: 300 }}
/>
}
>
<Table aria-label="users table">
<TableHead>
<TableRow>
<TableCell>ID</TableCell>
<TableCell>Name</TableCell>
<TableCell>Email</TableCell>
<TableCell>Actions</TableCell>
</TableRow>
</TableHead>
<TableBody>
{isLoading ? (
<TableRow>
<TableCell colSpan={4}>Loading...</TableCell>
</TableRow>
) : (
data?.data.map((user) => (
<TableRow key={user.id}>
<TableCell>{user.id}</TableCell>
<TableCell>{user.name}</TableCell>
<TableCell>{user.email}</TableCell>
<TableCell>
<EditButton recordItemId={user.id} />
<ShowButton recordItemId={user.id} />
<DeleteButton recordItemId={user.id} />
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</List>
);
};
export default UserList;实现创建页面
// src/pages/users/create.jsx
import { Create, Form, Input, Select, SaveButton } from '@refinedev/mui';
import { useForm } from '@refinedev/core';
const UserCreate = () => {
const { saveButtonProps, formValues } = useForm({
refineCoreProps: {
onSuccess: () => {
// 成功回调
},
},
});
return (
<Create>
<Form>
<Form.Item
label="Name"
name="name"
rules={[{ required: true, message: 'Name is required' }]}
>
<Input />
</Form.Item>
<Form.Item
label="Email"
name="email"
rules={[
{ required: true, message: 'Email is required' },
{ type: 'email', message: 'Invalid email format' },
]}
>
<Input />
</Form.Item>
<Form.Item
label="Role"
name="role"
rules={[{ required: true, message: 'Role is required' }]}
>
<Select
options={[
{ value: 'admin', label: 'Admin' },
{ value: 'user', label: 'User' },
]}
/>
</Form.Item>
<SaveButton {...saveButtonProps} />
</Form>
</Create>
);
};
export default UserCreate;实现编辑页面
// src/pages/users/edit.jsx
import { Edit, Form, Input, Select, SaveButton } from '@refinedev/mui';
import { useForm } from '@refinedev/core';
const UserEdit = () => {
const { saveButtonProps, formValues } = useForm({
refineCoreProps: {
onSuccess: () => {
// 成功回调
},
},
});
return (
<Edit>
<Form>
<Form.Item
label="Name"
name="name"
rules={[{ required: true, message: 'Name is required' }]}
>
<Input />
</Form.Item>
<Form.Item
label="Email"
name="email"
rules={[
{ required: true, message: 'Email is required' },
{ type: 'email', message: 'Invalid email format' },
]}
>
<Input />
</Form.Item>
<Form.Item
label="Role"
name="role"
rules={[{ required: true, message: 'Role is required' }]}
>
<Select
options={[
{ value: 'admin', label: 'Admin' },
{ value: 'user', label: 'User' },
]}
/>
</Form.Item>
<SaveButton {...saveButtonProps} />
</Form>
</Edit>
);
};
export default UserEdit;实现详情页面
// src/pages/users/show.jsx
import { Show, TextField, SimpleShowLayout, EditButton, DeleteButton } from '@refinedev/mui';
import { useShow } from '@refinedev/core';
const UserShow = () => {
const { queryResult } = useShow({
refineCoreProps: {
queryOptions: {
enabled: true,
},
},
});
const { data, isLoading } = queryResult;
return (
<Show>
<SimpleShowLayout
data={data?.data}
loading={isLoading}
>
<TextField source="id" label="ID" />
<TextField source="name" label="Name" />
<TextField source="email" label="Email" />
<TextField source="role" label="Role" />
<TextField source="createdAt" label="Created At" />
</SimpleShowLayout>
<div style={{ marginTop: '16px' }}>
<EditButton />
<DeleteButton />
</div>
</Show>
);
};
export default UserShow;使用数据提供者
// src/dataProvider.js
import { SimpleRest } from '@refinedev/simple-rest';
const API_URL = 'https://api.example.com';
const dataProvider = SimpleRest({
apiUrl: API_URL,
// 自定义请求头
defaultOptions: {
headers: {
'Content-Type': 'application/json',
},
},
// 自定义错误处理
handleError: (error) => {
console.error('API Error:', error);
return Promise.reject(error);
},
});
// 扩展数据提供者
const customDataProvider = {
...dataProvider,
// 自定义方法
getCustomData: async (params) => {
const response = await fetch(`${API_URL}/custom-endpoint`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
if (!response.ok) {
throw new Error('Failed to fetch custom data');
}
return {
data: await response.json(),
};
},
};
export default customDataProvider;高级特性
认证与授权
// src/authProvider.js
import { AuthProvider } from '@refinedev/core';
const authProvider = {
// 登录
login: async ({ username, password }) => {
const response = await fetch('https://api.example.com/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, password }),
});
if (!response.ok) {
throw new Error('Login failed');
}
const data = await response.json();
localStorage.setItem('token', data.token);
localStorage.setItem('user', JSON.stringify(data.user));
return {
success: true,
redirectTo: '/',
};
},
// 登出
logout: async () => {
localStorage.removeItem('token');
localStorage.removeItem('user');
return {
success: true,
redirectTo: '/login',
};
},
// 检查认证状态
check: async () => {
const token = localStorage.getItem('token');
if (!token) {
return {
authenticated: false,
redirectTo: '/login',
};
}
// 验证token
const response = await fetch('https://api.example.com/auth/me', {
headers: {
'Authorization': `Bearer ${token}`,
},
});
if (!response.ok) {
localStorage.removeItem('token');
localStorage.removeItem('user');
return {
authenticated: false,
redirectTo: '/login',
};
}
return {
authenticated: true,
};
},
// 获取权限
getPermissions: async () => {
const user = JSON.parse(localStorage.getItem('user'));
return user?.roles || [];
},
// 获取用户信息
getIdentity: async () => {
const user = JSON.parse(localStorage.getItem('user'));
return user;
},
// 更新密码
updatePassword: async ({ currentPassword, newPassword }) => {
const token = localStorage.getItem('token');
const response = await fetch('https://api.example.com/auth/change-password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
},
body: JSON.stringify({ currentPassword, newPassword }),
});
if (!response.ok) {
throw new Error('Password update failed');
}
return {
success: true,
};
},
};
export default authProvider;自定义路由
// src/routerProvider.js
import { RouterProvider } from '@refinedev/core';
import { BrowserRouter, Routes, Route, Outlet, Navigate } from 'react-router-dom';
import { Layout } from '@refinedev/mui';
const routerProvider = {
router: BrowserRouter,
routes: (
<Routes>
<Route element={<Layout />}>
<Route index element={<Navigate to="/users" replace />} />
<Route path="users">
<Route index element={<UserList />} />
<Route path="create" element={<UserCreate />} />
<Route path="edit/:id" element={<UserEdit />} />
<Route path="show/:id" element={<UserShow />} />
</Route>
<Route path="products">
<Route index element={<ProductList />} />
<Route path="create" element={<ProductCreate />} />
<Route path="edit/:id" element={<ProductEdit />} />
<Route path="show/:id" element={<ProductShow />} />
</Route>
{/* 自定义页面 */}
<Route path="dashboard" element={<Dashboard />} />
<Route path="settings" element={<Settings />} />
</Route>
<Route path="login" element={<LoginPage />} />
<Route path="*" element={<NotFound />} />
</Routes>
),
};
export default routerProvider;实时数据
// src/App.jsx
import { Refine } from '@refinedev/core';
import { LiveProvider } from '@refinedev/liveprovider-socketio';
const App = () => {
return (
<Refine
// ... 其他配置
liveProvider={{
subscribe: ({ channel, onMessage }) => {
// 实现订阅逻辑
const socket = io('https://socket.example.com');
socket.on(channel, (message) => {
onMessage(message);
});
return () => {
socket.off(channel);
};
},
unsubscribe: (args) => {
// 实现取消订阅逻辑
},
publish: (args) => {
// 实现发布逻辑
},
}}
resources={[
{
name: 'users',
// ... 其他配置
liveMode: 'auto', // 启用实时更新
},
]}
/>
);
};文件上传
// src/pages/products/create.jsx
import { Create, Form, Input, SaveButton, Upload } from '@refinedev/mui';
import { useForm } from '@refinedev/core';
const ProductCreate = () => {
const { saveButtonProps } = useForm();
return (
<Create>
<Form>
<Form.Item
label="Name"
name="name"
rules={[{ required: true, message: 'Name is required' }]}
>
<Input />
</Form.Item>
<Form.Item
label="Description"
name="description"
>
<Input />
</Form.Item>
<Form.Item
label="Image"
name="image"
rules={[{ required: true, message: 'Image is required' }]}
>
<Upload
maxFiles={1}
accept="image/*"
// 自定义上传逻辑
onUpload={(file) => {
const formData = new FormData();
formData.append('file', file);
return fetch('https://api.example.com/upload', {
method: 'POST',
body: formData,
})
.then((response) => response.json())
.then((data) => {
return {
url: data.url,
name: file.name,
};
});
}}
/>
</Form.Item>
<SaveButton {...saveButtonProps} />
</Form>
</Create>
);
};
export default ProductCreate;国际化
// src/i18n.js
import { I18nProvider } from '@refinedev/core';
const i18nProvider = {
translate: (key, options) => {
// 实现翻译逻辑
const translations = {
'users': '用户',
'products': '产品',
'dashboard': '仪表盘',
'settings': '设置',
'login': '登录',
'logout': '登出',
'create': '创建',
'edit': '编辑',
'delete': '删除',
'save': '保存',
'cancel': '取消',
'search': '搜索',
'filter': '筛选',
'sort': '排序',
'refresh': '刷新',
'pagination': {
'showing': '显示',
'to': '到',
'of': '共',
'results': '条结果',
},
'auth': {
'login': {
'title': '登录',
'username': '用户名',
'password': '密码',
'submit': '登录',
'forgotPassword': '忘记密码',
},
},
};
return translations[key] || key;
},
changeLocale: (locale) => {
// 实现切换语言逻辑
localStorage.setItem('locale', locale);
return Promise.resolve();
},
getLocale: () => {
// 获取当前语言
return localStorage.getItem('locale') || 'zh-CN';
},
};
export default i18nProvider;// src/App.jsx
import { Refine } from '@refinedev/core';
import i18nProvider from './i18n';
const App = () => {
return (
<Refine
// ... 其他配置
i18nProvider={i18nProvider}
/>
);
};实用场景
管理面板
功能需求:创建一个完整的用户管理面板,支持用户的增删改查、筛选、排序和分页。
实现步骤:
配置资源:
resources={[ { name: 'users', list: '/users', create: '/users/create', edit: '/users/edit/:id', show: '/users/show/:id', meta: { label: 'Users', icon: <UsersIcon />, }, }, ]}创建用户列表页面:
- 添加表格组件展示用户列表
- 实现筛选、排序和分页功能
- 添加编辑、删除和查看详情按钮
创建用户创建页面:
- 添加表单组件
- 实现表单验证
- 添加文件上传功能(头像)
创建用户编辑页面:
- 预填充表单数据
- 实现表单验证
- 添加文件上传功能(头像)
创建用户详情页面:
- 展示用户详细信息
- 添加编辑和删除按钮
配置权限:
- 设置不同角色的访问权限
- 限制敏感操作
电子商务后台
功能需求:创建一个电子商务后台管理系统,支持产品、订单和客户管理。
实现步骤:
配置资源:
resources={[ { name: 'products', list: '/products', create: '/products/create', edit: '/products/edit/:id', show: '/products/show/:id', meta: { label: 'Products', icon: <ProductsIcon />, }, }, { name: 'orders', list: '/orders', edit: '/orders/edit/:id', show: '/orders/show/:id', meta: { label: 'Orders', icon: <OrdersIcon />, }, }, { name: 'customers', list: '/customers', show: '/customers/show/:id', meta: { label: 'Customers', icon: <CustomersIcon />, }, }, ]}创建产品管理页面:
- 支持产品分类
- 实现产品图片上传
- 支持库存管理
创建订单管理页面:
- 展示订单状态
- 支持订单状态更新
- 显示订单详情和配送信息
创建客户管理页面:
- 展示客户基本信息
- 显示客户订单历史
- 支持客户分组和标签
添加仪表盘:
- 显示销售统计
- 展示热门产品
- 显示订单趋势
内容管理系统
功能需求:创建一个内容管理系统,支持文章、分类和标签管理。
实现步骤:
配置资源:
resources={[ { name: 'posts', list: '/posts', create: '/posts/create', edit: '/posts/edit/:id', show: '/posts/show/:id', meta: { label: 'Posts', icon: <PostsIcon />, }, }, { name: 'categories', list: '/categories', create: '/categories/create', edit: '/categories/edit/:id', meta: { label: 'Categories', icon: <CategoriesIcon />, }, }, { name: 'tags', list: '/tags', create: '/tags/create', edit: '/tags/edit/:id', meta: { label: 'Tags', icon: <TagsIcon />, }, }, ]}创建文章管理页面:
- 支持富文本编辑器
- 实现文章分类和标签关联
- 支持文章状态管理(草稿、发布)
创建分类管理页面:
- 支持分类层级结构
- 实现分类排序
- 显示分类下的文章数量
创建标签管理页面:
- 支持标签创建和编辑
- 显示标签使用次数
- 支持标签搜索
添加媒体库:
- 支持图片上传和管理
- 实现图片分类
- 支持图片搜索和预览
最佳实践
项目结构:
- 按功能模块组织代码
- 使用组件化和模块化设计
- 分离关注点,如数据逻辑、UI组件和业务逻辑
数据管理:
- 合理设计数据模型和API接口
- 使用适当的数据提供者
- 实现数据缓存和优化
认证与授权:
- 实现安全的认证机制
- 使用细粒度的权限控制
- 保护敏感数据和操作
UI/UX设计:
- 遵循现代UI设计原则
- 实现响应式布局
- 提供良好的用户反馈
性能优化:
- 实现代码分割和懒加载
- 优化API请求
- 使用缓存减少重复请求
测试:
- 编写单元测试和集成测试
- 测试边界情况和错误处理
- 使用模拟数据进行开发和测试
部署:
- 优化构建配置
- 实现CI/CD流程
- 监控应用性能和错误
文档:
- 编写清晰的API文档
- 提供用户指南和教程
- 记录代码注释和设计决策
国际化:
- 支持多语言
- 考虑不同地区的文化差异
- 使用统一的国际化方案
安全:
- 防止常见的安全漏洞
- 实现HTTPS和CORS
- 定期更新依赖和安全补丁
常见问题与解决方案
1. 数据提供者配置问题
问题:无法连接到后端API或数据获取失败
解决方案:
- 检查API URL是否正确
- 验证请求头和认证令牌
- 测试API端点是否可访问
- 查看浏览器控制台和网络请求
- 检查数据提供者配置
2. 认证问题
问题:用户无法登录或认证失败
解决方案:
- 检查认证提供者配置
- 验证用户名和密码
- 检查认证API端点
- 查看令牌存储和管理
- 检查权限配置
3. 路由问题
问题:页面无法访问或路由错误
解决方案:
- 检查路由提供者配置
- 验证路由路径和参数
- 检查资源配置
- 测试导航链接
- 查看浏览器控制台错误
4. 表单验证问题
问题:表单验证不工作或错误消息不正确
解决方案:
- 检查表单规则配置
- 验证表单字段名称
- 测试不同的输入场景
- 查看表单组件文档
- 检查错误消息配置
5. 实时数据问题
问题:实时数据更新不工作或延迟
解决方案:
- 检查实时提供者配置
- 验证WebSocket连接
- 测试消息订阅和发布
- 检查网络连接
- 查看服务器日志
6. 文件上传问题
问题:文件上传失败或进度不显示
解决方案:
- 检查上传配置
- 验证文件大小和类型限制
- 测试上传API端点
- 检查网络连接
- 查看浏览器控制台错误
7. 国际化问题
问题:翻译不显示或语言切换不工作
解决方案:
- 检查国际化提供者配置
- 验证翻译键和值
- 测试语言切换功能
- 检查默认语言设置
- 查看浏览器控制台错误
8. 性能问题
问题:应用加载缓慢或操作响应延迟
解决方案:
- 优化API请求
- 实现数据缓存
- 使用代码分割和懒加载
- 优化组件渲染
- 检查网络连接速度
9. 主题定制问题
问题:主题设置不生效或样式冲突
解决方案:
- 检查主题配置
- 验证CSS优先级
- 测试不同的主题选项
- 检查样式导入顺序
- 查看浏览器控制台错误
10. 部署问题
问题:应用部署失败或无法访问
解决方案:
- 检查构建配置
- 验证服务器设置
- 测试API连接
- 检查环境变量
- 查看服务器日志
与其他框架的比较
Refine vs React Admin
- 设计理念:Refine更注重灵活性和可扩展性,React Admin更注重开箱即用的功能
- UI组件:Refine支持多种UI库,React Admin主要使用Material-UI
- 数据集成:两者都支持多种后端API集成
- 学习曲线:Refine学习曲线较平缓,React Admin相对复杂
- 生态系统:React Admin生态系统更成熟,Refine正在快速发展
- 社区支持:两者都有活跃的社区
Refine vs RedwoodJS
- 架构:Refine是前端框架,RedwoodJS是全栈框架
- 后端集成:RedwoodJS内置后端,Refine需要外部后端
- 数据库支持:RedwoodJS支持多种数据库,Refine依赖后端API
- 部署:RedwoodJS提供完整的部署方案,Refine需要自定义部署
- 学习曲线:RedwoodJS学习曲线较陡,Refine相对简单
Refine vs Next.js
- 定位:Refine专注于数据密集型应用,Next.js是通用React框架
- 功能:Refine提供内置的CRUD操作和数据管理,Next.js需要自定义实现
- 生态系统:Next.js生态系统更丰富,Refine更专注于特定领域
- 性能:两者都注重性能优化
- 使用场景:Refine适合管理面板和CRM系统,Next.js适合各种类型的应用
参考资源
- 官方文档:https://refine.dev/docs/
- GitHub 仓库:https://github.com/refinedev/refine
- 官方教程:https://refine.dev/docs/tutorial/introduction/index/
- 示例应用:https://refine.dev/examples/
- API文档:https://refine.dev/docs/api-reference/core/
- 社区论坛:https://discord.gg/refine
- 视频教程:https://www.youtube.com/c/RefineDev
- 贡献指南:https://refine.dev/docs/contributing/
- 变更日志:https://refine.dev/docs/changelog/
- 常见问题:https://refine.dev/docs/faq/