ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Material UI 路由库集成指南:用 Link、Button 对接 react-router、Next.js 与 TanStack Router

Material UI 路由库集成指南:用 Link、Button 对接 react-router、Next.js 与 TanStack Router Material UI 路由库集成指南用 Link、Button 对接 react-router、Next.js 与 TanStack Router【免费下载链接】material-uiMaterial UI: Comprehensive React component library that implements Googles Material Design. Free forever.项目地址: https://gitcode.com/GitHub_Trending/ma/material-ui本文基于 Material UI 官方文档 Routing libraries 展开讲解如何把 Material UI 的导航组件与第三方路由库集成默认情况下导航由原生a元素完成你可以将其替换为 react-router 的Link、Next.js 的Link或 TanStack Router 的createLink。读完本文你将掌握三种集成手段——单组件的componentprop、全局主题级LinkComponent/defaultProps配置以及面向 Next.js Pages Router 的适配器组件写法并了解ButtonBase内部将按钮切换为链接模式的实现原理。导航组件Link 与启用链接模式的 ButtonMaterial UI 中承担导航职责的核心组件有两个Link从名字就能看出用途它渲染一个原生a元素并把href作为属性应用上去。最基础的用法import Link from mui/material/Link; import Box from mui/material/Box; export default function LinkDemo() { return ( Box sx{{ typography: body1 }} Link href/Link/Link /Box ); }任何扩展了ButtonBase的组件如Button都可以通过提供hrefprop 进入“链接模式”import Button from mui/material/Button; export default function ButtonDemo() { return ( Button href/ variantcontained Link /Button ); }从源码结构看这个“按钮变链接”的行为由ButtonBase的实现直接决定。在 ButtonBase.js 中可以看到LinkComponent的默认值为aLinkComponent a,随后组件会判断“是否以链接意图渲染”并在component为button时将其替换为LinkComponentButtonBase.jsconst isLink Boolean(other.href || other.to); ... let ComponentProp component; if (ComponentProp button isLink) { ComponentProp LinkComponent; }也就是说只要href或to任一 prop 存在Material UI 就认为该组件应当渲染为链接而LinkComponent正是后面“全局替换路由库 Link”的挂载点。这一机制也被测试用例覆盖ButtonBase.test.js 中的 “should use custom LinkComponent when provided in the theme” 验证了通过主题注入自定义LinkComponent后ButtonBase href...确实渲染为自定义链接组件。全局主题级 Link一次配置全应用生效在实际应用中单纯的原生a往往不够用——你可能需要客户端路由带来的无刷新导航。Material UI 的主题允许你把这个“增强版 Link”一次性配置到全局。以 react-router 为例对应示例 LinkRouterWithTheme.tsximport { Link as RouterLink, LinkProps as RouterLinkProps } from react-router; import { LinkProps } from mui/material/Link; const LinkBehavior React.forwardRef HTMLAnchorElement, OmitRouterLinkProps, to { href: RouterLinkProps[to] } ((props, ref) { const { href, ...other } props; // Map href (Material UI) - to (react-router) return RouterLink ref{ref} to{href} {...other} /; }); const theme createTheme({ components: { MuiLink: { defaultProps: { component: LinkBehavior, } as LinkProps, }, MuiButtonBase: { defaultProps: { LinkComponent: LinkBehavior, }, }, }, });这里做了两件配合的事MuiLink.defaultProps.component让所有Link组件默认走LinkBehavior把 Material UI 语义的href映射到 react-router 的toMuiButtonBase.defaultProps.LinkComponent覆盖了上文源码中LinkComponent a的默认值使所有 Button 系组件在链接模式下同样走LinkBehavior。配置完成后Link href/和Button href/都不需要再逐个传component。TypeScript 限制该方案在 TypeScript 下有一个局限——hrefprop 只接受字符串。如果你需要传递更丰富的结构如 Next.js 的{ pathname, query }对象见下文基于componentprop 的写法。componentprop逐组件集成路由库不依赖全局主题时可以直接通过componentprop 完成与第三方路由库的集成。该 prop 的完整语义包括 props 透传规则在 组合指南 的 component prop 一节有说明。以 react-router 为例对应示例 LinkRouter.tsxconst LinkBehavior React.forwardRefany, OmitRouterLinkProps, to | href( (props, ref) ( RouterLink ref{ref} to/material-ui/getting-started/installation/ {...props} / ), ); Link component{RouterLink} to/With prop forwarding/Link Link component{LinkBehavior}Without prop forwarding/Link两种写法的区别在于 props 透传策略With prop forwarding直接把RouterLink作为componentMaterial UI 会把to等 prop 原样透传给路由库组件Without prop forwardingWith inlining通过forwardRef自定义LinkBehavior包装层在内部自行控制属性映射例如固定to值、把href重映射为to适合路由库 API 与 Material UI prop 命名不一致的场景。React Router 实战Link、Button、Tabs、List同一套策略可以应用到所有导航类组件BottomNavigation、Card、Tabs、List 等。官方示例文件均位于 docs/data/material/integrations/routing/ 目录。Link即上节所示Link component{RouterLink} to/或配合LinkBehavior包装层使用。Button 与role属性陷阱对应示例 ButtonRouter.tsxconst LinkBehavior React.forwardRefany, OmitRouterLinkProps, to( (props, ref) RouterLink ref{ref} to/ {...props} role{undefined} /, ); export default function ButtonRouter() { return ( Router Button component{RouterLink} to/ With prop forwarding /Button Button component{LinkBehavior}With inlining/Button /Router ); }这里有一个容易踩的坑ButtonBase 在识别到“用非原生button元素渲染按钮”的意图时会附加rolebutton属性。当渲染的其实是一个链接时这个role会造成可访问性问题。因此如果你没有使用href、to或componenta这三个 prop 之一就需要覆盖role属性——上面的示例通过在展开 props 之后设置role{undefined}来清除它。Tabs按路由模式高亮当前标签对应示例 TabsRouter.tsx 的关键点是用 react-router 的matchPath计算当前激活的 Tabfunction MyTabs() { // 路由模式需要按“后代优先”的顺序提供 // 例如嵌套路由 users, users/new, users/edit // 顺序应为 [users/add, users/edit, users] const routeMatch useRouteMatch([/inbox/:id, /drafts, /trash]); const currentTab routeMatch?.pattern?.path; return ( Tabs value{currentTab} Tab labelInbox value/inbox/:id to/inbox/1 component{Link} / Tab labelDrafts value/drafts to/drafts component{Link} / Tab labelTrash value/trash to/trash component{Link} / /Tabs ); }两个细节值得注意Tab通过tocomponent{Link}实现点击导航而value必须与路由模式字符串保持一致才能让matchPath命中后正确高亮。由于匹配是从前到后遍历带参数的模式如/inbox/:id必须排在更宽泛的模式之前。ListListItemButton 接入路由对应示例 ListRouter.tsx 封装了一个列表项链接组件function ListItemLink(props: ListItemLinkProps) { const { icon, primary, to } props; return ( ListItemButton component{Link} to{to} {icon ? ListItemIcon{icon}/ListItemIcon : null} ListItemText primary{primary} / /ListItemButton ); }ListItemButton同样扩展自ButtonBase因此component{Link}to即可让列表项具备 react-router 的客户端导航能力示例中 Inbox / Drafts / Trash / Spam 四个文件夹都以此方式接入。Next.js Pages Router官方示例仓库中的适配器仓库中的 examples/material-ui-nextjs-pages-router-ts 示例文件夹提供了 Next.jsLink与 Material UI 的适配方案核心实现在 src/Link.tsx。该文件导出了两版适配器NextLinkComposed第一版适配器不带样式只负责处理导航。它把 prophref重命名为to以避免命名冲突与 react-router 的 Link 组件同理export const NextLinkComposed React.forwardRefHTMLAnchorElement, NextLinkComposedProps( function NextLinkComposed(props, ref) { const { to, linkAs, ...other } props; return NextLink href{to} as{linkAs} ref{ref} {...other} /; }, );使用方式import Button from mui/material/Button; import { NextLinkComposed } from ../src/Link; export default function Index() { return ( Button component{NextLinkComposed} to{{ pathname: /about, query: { name: test }, }} Button link /Button ); }Link第二版适配器是带样式的版本——它内部使用 Material UI 的Link组件并搭配NextLinkComposed同时通过useRouter比较router.pathname与目标路径为当前激活的链接自动附加activeClassName默认active。它还支持noLinkStyleprop开启后返回未套样式的NextLinkComposed。使用方式import Link from ../src/Link; export default function Index() { return ( Link href{{ pathname: /about, query: { name: test }, }} Link /Link ); }这个适配器的存在恰好回应了上文主题方案的 TypeScript 局限由于 Next.js 的href可以接收{ pathname, query }这类非字符串结构只能走componentprop 路径而非主题级href映射。TanStack Router使用 createLink 定制链接TanStack Router 通过createLink辅助函数支持自定义链接组件。下面的片段是最基本的实现包裹一个 Material UI Link 组件import { createLink } from tanstack/react-router; import { Link as MUILink } from mui/material; const CustomLink createLink(MUILink); function App() { return ( CustomLink underlinenone to/about Link to about page /CustomLink ); }createLink(MUILink)返回的组件会自动处理to等路由 props 与a语义的对接Material UI 侧只需保持常规样式属性如underlinenone。参考路径汇总内容仓库路径本文主体文档docs/data/material/integrations/routing/routing.mdLink / Button 基础示例LinkDemo.tsx、ButtonDemo.tsx主题级全局 Link 示例LinkRouterWithTheme.tsxreact-router 各组件示例LinkRouter.tsx、ButtonRouter.tsx、TabsRouter.tsx、ListRouter.tsxNext.js Pages Router 适配器examples/material-ui-nextjs-pages-router-ts/src/Link.tsxButtonBase 链接模式实现packages/mui-material/src/ButtonBase/ButtonBase.jsLinkComponent 主题注入测试packages/mui-material/src/ButtonBase/ButtonBase.test.jscomponent prop 组合语义docs/data/material/guides/composition/composition.md选择建议如果只是少量组件需要路由导航用componentprop 最直接如果应用内绝大多数导航都要走客户端路由优先采用主题级MuiLinkMuiButtonBase.LinkComponent一次性配置注意href仅限字符串使用 Next.js Pages Router 且需要对象形式的href时参考官方示例仓库中的NextLinkComposed/Link适配器实现。【免费下载链接】material-uiMaterial UI: Comprehensive React component library that implements Googles Material Design. Free forever.项目地址: https://gitcode.com/GitHub_Trending/ma/material-ui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表