ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Refine 教程实战:结合 Material UI 与 React Router 搭建带主题布局的 CRUD 应用

Refine 教程实战:结合 Material UI 与 React Router 搭建带主题布局的 CRUD 应用 Refine 教程实战结合 Material UI 与 React Router 搭建带主题布局的 CRUD 应用【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine本篇基于 Refine 官方教程中的 Material UI 章节讲解如何在一个已完成路由集成的 Refine 项目中引入 Material UI安装refinedev/mui及相关 MUI 依赖、使用RefineThemes预置主题包裹应用、挂载CssBaseline与GlobalStyles重置浏览器默认样式并用ThemedLayout /一步获得侧边栏与头部布局。读完本文你将掌握 Refine MUI 集成的主题体系与布局组件的工作原理并能对照仓库源码理解每个组件背后的实现。本单元的定位与整体目标该章节位于教程「UI Libraries」部分的 Material UI 子线教程原文承接前一单元「Refine 的路由集成」目标是基于refinedev/react-router与 Material UI 共同构建一个完整的 CRUD 应用。Refine 为 Material UI、Ant Design、Chakra UI 和 Mantine 等主流 UI 库提供官方集成这些集成提供了一组组件与 Hooks简化表单与表格管理、布局、视图、按钮等开发工作官方文档详见 Material UI 集成文档目录。本单元覆盖的主题包括使用布局组件为应用添加菜单、头部、面包屑和认证管理使用 CRUD 视图组件创建设计一致、功能统一的动作页面使用 Hooks 将表单元素和表格与 Refine 的useTable、useForm集成使用notistack将 Refine 的通知系统与 Material UI 的通知能力打通使用AuthPage /组件管理认证页面。注意Material UI 自带表单元素但不提供表单状态管理方案。教程后续会引入 Refine 的 React Hook Form 集成包refinedev/react-hook-form基于 RefineuseFormHook 的扩展来管理表单状态其安装会在重构表单组件的步骤中进行。添加 Material UI 依赖要使用 Material UI 组件并访问 Refine 的集成 Hooks 与组件需要安装refinedev/mui包。完整依赖如下npm install refinedev/mui emotion/react emotion/styled mui/lab mui/material mui/x-data-grid其中emotion/react与emotion/styled是 MUI 的样式引擎mui/material是核心组件库mui/lab提供实验性组件如Autocomplete的异步加载模式mui/x-data-grid则用于 Refine 表格集成。教程的 Sandpack 沙箱配置 中锁定了实际使用的版本组合mui/material为 6.x、mui/x-data-grid为 7.x、refinedev/mui取 latest可作为实操时的版本参考。用 ThemeProvider 挂载主题与全局样式重置应用需要用 MUI 的ThemeProvider /包裹来设定主题并挂载CssBaseline /与GlobalStyles /重置浏览器的默认样式。ThemeProvider /需要传入themepropRefine 提供了预置主题RefineThemes覆盖多种色彩方案与暗色模式可以直接用于加速开发并保持应用设计一致。按教程更新src/App.tsximport { Refine, Authenticated } from refinedev/core; import routerProvider, { NavigateToResource } from refinedev/react-router; import { BrowserRouter, Routes, Route, Outlet } from react-router; // highlight-next-line import { RefineThemes } from refinedev/mui; // highlight-start import CssBaseline from mui/material/CssBaseline; import GlobalStyles from mui/material/GlobalStyles; import { ThemeProvider } from mui/material/styles; // highlight-end import { dataProvider } from ./providers/data-provider; import { authProvider } from ./providers/auth-provider; import { ShowProduct } from ./pages/products/show; import { EditProduct } from ./pages/products/edit; import { ListProducts } from ./pages/products/list; import { CreateProduct } from ./pages/products/create; import { Login } from ./pages/login; import { Header } from ./components/header; export default function App(): JSX.Element { return ( BrowserRouter {/* highlight-start */} {/* Were using Refines Blue theme here. You can use other variants or create your own theme without constraints. */} ThemeProvider theme{RefineThemes.Blue} CssBaseline / GlobalStyles styles{{ html: { WebkitFontSmoothing: auto } }} / {/* highlight-end */} Refine dataProvider{dataProvider} authProvider{authProvider} routerProvider{routerProvider} resources{[ { name: protected-products, list: /products, show: /products/:id, edit: /products/:id/edit, create: /products/create, meta: { label: Products }, }, ]} Routes Route element{ Authenticated keyauthenticated-routes redirectOnFail/login Header / Outlet / /Authenticated } Route index element{NavigateToResource resourceprotected-products /} / Route path/products Route index element{ListProducts /} / Route path:id element{ShowProduct /} / Route path:id/edit element{EditProduct /} / Route pathcreate element{CreateProduct /} / /Route /Route Route element{ Authenticated keyauth-pages fallback{Outlet /} NavigateToResource resourceprotected-products / /Authenticated } Route path/login element{Login /} / /Route /Routes /Refine {/* highlight-start */} /ThemeProvider {/* highlight-end */} /BrowserRouter ); }从源码看 RefineThemes 的生成机制RefineThemes并非手工逐个编写而是在 packages/mui/src/theme/index.ts 中由色板表程序化生成const RefineThemes Object.keys(RefinePalettes).reduce((acc, key) { const paletteName key as keyof typeof RefinePalettes; return { ...acc, [key]: createTheme({ palette: { ...RefinePalettes[paletteName] }, components: { MuiButton: { styleOverrides: { root: ({ ownerState }) ({ ...(ownerState.variant contained ownerState.color primary { color: #fff, }), }), }, }, }, }), }; }, {}) as Recordkeyof typeof RefinePalettes, Theme;色板定义在 packages/mui/src/theme/palette/refinePalette.ts共 6 组色彩每组各提供浅色与深色两个变体合计 12 个主题主题模式primary.mainBlue/BlueDarklight / dark#1976D2/#67b7f7Purple/PurpleDarklight / dark#7B1FA2/#AB47BCMagenta/MagentaDarklight / dark#C2185B/#EC407ARed/RedDarklight / dark#D32F2F/#EF5350Orange/OrangeDarklight / dark#F57C00/#FFA726Yellow/YellowDarklight / dark#FFA000/#FFCA28Green/GreenDarklight / dark#689F38/#9CCC65同文件还额外导出了两个完整的LightTheme与DarkTheme二者共享shape.borderRadius: 6与统一的typography分别使用 lightPalette 与 darkPalette 定义完整调色板并对MuiAppBar、MuiPaper、MuiTypography做了针对性覆盖例如浅色主题中 AppBar 背景设为白色、h5标题加粗至 800。从源码结构看如果你的应用需要比RefineThemes更完整的光暗双模式可以改用LightTheme/DarkTheme并自行调整palette。用 ThemedLayout 挂载布局教程的下一步是用 Refine 提供的ThemedLayout /包裹受认证保护的根路由它自带侧边栏、头部、面包屑等开箱即用能力。更新后的src/App.tsx相对上一步的增量是把Header /替换为ThemedLayoutimport { Refine, Authenticated } from refinedev/core; import routerProvider, { NavigateToResource } from refinedev/react-router; import { BrowserRouter, Routes, Route, Outlet } from react-router; // highlight-next-line import { RefineThemes, ThemedLayout } from refinedev/mui; import CssBaseline from mui/material/CssBaseline; import GlobalStyles from mui/material/GlobalStyles; import { ThemeProvider } from mui/material/styles; import { dataProvider } from ./providers/data-provider; import { authProvider } from ./providers/auth-provider; import { ShowProduct } from ./pages/products/show; import { EditProduct } from ./pages/products/edit; import { ListProducts } from ./pages/products/list; import { CreateProduct } from ./pages/products/create; import { Login } from ./pages/login; export default function App(): JSX.Element { return ( BrowserRouter ThemeProvider theme{RefineThemes.Blue} CssBaseline / GlobalStyles styles{{ html: { WebkitFontSmoothing: auto } }} / Refine dataProvider{dataProvider} authProvider{authProvider} routerProvider{routerProvider} resources{[ { name: protected-products, list: /products, show: /products/:id, edit: /products/:id/edit, create: /products/create, meta: { label: Products }, }, ]} Routes Route element{ Authenticated keyauthenticated-routes redirectOnFail/login {/* highlight-start */} ThemedLayout Outlet / /ThemedLayout {/* highlight-end */} /Authenticated } Route index element{NavigateToResource resourceprotected-products /} / Route path/products Route index element{ListProducts /} / Route path:id element{ShowProduct /} / Route path:id/edit element{EditProduct /} / Route pathcreate element{CreateProduct /} / /Route /Route Route element{ Authenticated keyauth-pages fallback{Outlet /} NavigateToResource resourceprotected-products / /Authenticated } Route path/login element{Login /} / /Route /Routes /Refine /ThemeProvider /BrowserRouter ); }至此应用就被一个带侧边栏和头部的完整布局包裹了。ThemedLayout 的源码结构从 packages/mui/src/components/themedLayout/index.tsx 的实现看ThemedLayout接受以下关键 propsProp说明Sider/Header/Title/Footer自定义布局区块不传时使用内置的ThemedSider、ThemedHeader等默认实现OffLayoutArea渲染在 Sider 与主区域之外的附加区域通常用于UnsavedChangesNotifier等全局弹层initialSiderCollapsed/onSiderCollapsed侧边栏初始折叠状态与折叠状态回调childrenBoxProps/containerBoxProps传给内容容器与外层容器的BoxProps含sx用于微调间距、背景等其内部渲染结构为ThemedLayoutContextProvider提供侧边栏折叠状态的上下文外层是一个横向 Flex 容器Sider 固定在左侧右侧纵向排列Header、内容main响应式内边距p: { xs: 1, md: 2, lg: 3 }背景取自theme.palette.background.default以及可选的FooterOffLayoutArea挂在最外层 Flex 容器末尾。侧边栏与头部的拆分实现在 sider、header 子目录中配套的HamburgerMenu、ThemedTitle也一并导出见 components/index.tsx后续步骤会逐一展开这些布局特性。refinedev/mui 的完整能力面依赖装好、主题与布局就位后这个包实际提供的能力可以从其入口 packages/mui/src/index.tsx 与 packages/mui/src/components/index.tsx 看到全貌与本单元后续主题一一对应布局组件ThemedLayout、ThemedSider、ThemedTitle、ThemedHeader、HamburgerMenu认证页面components/pages/auth下的Login、Register、ForgotPassword、UpdatePassword及统一导出的AuthPage /对应主题列表中的第 5 项CRUD 视图CreateView、EditView、ListView、ShowView等保证四个动作页设计与交互一致按钮组件CreateButton、EditButton、DeleteButton、ShowButton、ListButton、RefreshButton、SaveButton、ImportButton、ExportButton、CloneButton以及面包屑Breadcrumb表单字段BooleanInput、DateInput、EmailInput、FileInput、MarkdownInput、NumberInput、TextInput、TagInput、UrlInput等通知集成RefineSnackbarProvider、useNotificationProvider并直接转出notistack的SnackbarProvider、useSnackbar等 APIHooksuseAutocomplete、useDataGrid、useThemedLayoutContext见 packages/mui/src/hooks/index.ts。参考仓库中的完整示例examples/tutorial-material-ui仓库内 examples/tutorial-material-ui 是该教程线的可运行落地版本其 src/App.tsx 展示了本单元各步骤完成后的「完整形态」——在本章代码基础上进一步加入通知与体验组件BrowserRouter GitHubBanner / ThemeProvider theme{RefineThemes.Blue} CssBaseline / GlobalStyles styles{{ html: { WebkitFontSmoothing: auto } }} / RefineSnackbarProvider Refine routerProvider{routerProvider} dataProvider{dataProvider(https://api.fake-rest.refine.dev)} notificationProvider{useNotificationProvider} resources{[{ name: blog_posts, /* ... */ }]} options{{ syncWithLocation: true, warnWhenUnsavedChanges: true }} ThemedLayout Routes {/* ... index 与 /blog-posts 下的 list/show/create/edit 路由 ... */} Route path* element{ErrorComponent /} / /Routes /ThemedLayout UnsavedChangesNotifier / DocumentTitleHandler / /Refine /RefineSnackbarProvider /ThemeProvider /BrowserRouter相比教程本章它额外演示了三点一是RefineSnackbarProvider包裹Refine并注入useNotificationProvider作为notificationProvider这正是主题列表中「使用 notistack 集成通知」的落地方式二是UnsavedChangesNotifier与options.warnWhenUnsavedChanges: true配合防止表单未保存时误跳转三是使用ErrorComponent兜底未匹配路由。该示例使用refinedev/simple-rest对接api.fake-rest.refine.dev无需后端即可跑通适合作为本文步骤完成后的验证参照。小结本章完成了 Material UI 集成的两块基石依赖与主题安装refinedev/mui与 MUI 全家桶用ThemeProvider theme{RefineThemes.Blue}挂载预置主题并配合CssBaseline、GlobalStyles完成样式基线RefineThemes的 12 个色板主题由源码中的RefinePalettes程序化生成另有LightTheme/DarkTheme可用于完整光暗模式场景。布局用ThemedLayout /包裹受认证保护的路由出口一步获得侧边栏、头部与面包屑能力其Sider/Header/Footer/OffLayoutArea等 props 与ThemedLayoutContext为后续深度定制留出了扩展点。后续步骤将依次深入布局组件的菜单/认证区细节、ListView/CreateView等 CRUD 视图、基于useTable与useForm的表格与表单集成、notistack通知接线以及AuthPage /认证页面的使用。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进