React Material UI - 当没有子项与提供的值匹配时处理导航选项卡

Posted

技术标签:

【中文标题】React Material UI - 当没有子项与提供的值匹配时处理导航选项卡【英文标题】:React Material UI - Handle nav tabs when no children match the provided value 【发布时间】:2022-01-04 08:27:39 【问题描述】:

我的应用中有一个 NavBar,它使用带有 React Router v4 的 Material UI v5 - Nav tabs 组件。因此,当您导航到 /about-us 之类的内容时,它会从 url 读取该内容,然后切换到该选项卡。

问题

我有子页面,例如 /about-us/john/about-us/deborah,但是当我导航到这些页面时,我收到如下错误:

MUI:提供给 Tabs 组件的value 无效。

所有选项卡的子项都不匹配“/about-us/john”。

您可以提供以下值之一:/、/about-us。

您将在我当前方法下方的示例代码部分中看到,我正在考虑是否有办法拥有“有效”标签 URL 列表,但是当有描述的子页面时不确定如何处理以上。

期望的结果

当我导航到像 /about-us/john 这样的 URL 时,它:

不会抛出上述错误。 [很高兴] 仍然突出显示 About Us 选项卡。

示例代码

// NavBar.tsx
import  Link, useLocation  from 'react-router-dom';
import Tabs from '@mui/material/Tabs';
import Tab from '@mui/material/Tab';

export const NavBar = () => 
  const location = useLocation();
  const currentTab = location.pathname;

  return (
    <Tabs value=currentTab >
      <Tab label="Home" value="/" to="/" component=Link />
      <Tab label="About Us" value="/about-us" to="/about-us" component=Link />
    </Tabs>
  );

// App.tsx
import  BrowserRouter as Router, Switch, Route from 'react-router-dom';
import NavBar from './NavBar';
import Home from './Home';
import AboutUs from './AboutUs';
import AboutUsDetail from './AboutUsDetail';

export const App = () => 
  return (
    <Router>
      <NavBar />
      <Switch>
        <Route exact path="/">
          <Home />
        </Route>
        <Route exact path="/about-us">
          <AboutUs />
        </Route>
        <Route exact path="/about-us/:name">
          // Uses `useParams` from react-router-dom to extract the name.
          <AboutUsDetail />
        </Route>
      </Switch>
    </Router>
  );
;

【问题讨论】:

【参考方案1】:

问题

当匹配和渲染更深的“嵌套”路径时,即"/about-us/john",没有指定匹配的Tab组件value属性来正确渲染选项卡。

解决方案

NavBar 为例,您实际上只需要匹配任何路由的“根”路径段,在这种情况下,可以是"/""/about-us"。可能有几种方法可以实现这一点,即字符串拆分、正则表达式等……下面的示例使用带有捕获组的正则表达式来获取第一段。 /^(\/[^\/]*)/g 从匹配 "/" 的字符串的开头开始匹配,并包括直到字符串结尾或下一个 "/" 字符的所有字符。

console.log([..."/".matchAll(/^(\/[^/]*)/g)][0][1]);
console.log([..."/about-us".matchAll(/^(\/[^/]*)/g)][0][1]);
console.log([..."/about-us/john".matchAll(/^(\/[^/]*)/g)][0][1]);
const NavBar = () => 
  const location = useLocation();

  const [[, currentRoot]] = location.pathname.matchAll(/^(\/[^/]*)/g);

  return (
    <Tabs value=currentRoot>
      <Tab label="Home" value="/" to="/" component=Link />
      <Tab label="About Us" value="/about-us" to="/about-us" component=Link />
    </Tabs>
  );
;

只是关于将路由渲染到Switch 的一个不相关的旁注,您可以通过正确地将路由从更具体的路径排序到不太具体的路径来避免不必要地使用exact 属性。如果没有更高、更具体的路由匹配,则继续匹配,直到找到并呈现最不具体的匹配。

<Switch>
  <Route path="/about-us/:name">
    <AboutUsDetail />
  </Route>
  <Route path="/about-us">
    <AboutUs />
  </Route>
  <Route path="/">
    <Home />
  </Route>
</Switch>

【讨论】:

这太棒了,谢谢@Drew Reese!欣赏旁注,我记得在文档中阅读并忘记应用它,将更新代码以匹配!最后一件小事,我在我的项目中使用 Typescript,并且在 ReGex 行 Type 'RegExpExecArray | null' is not an array type.ts(2461) 上遇到了这个错误,你将如何解决这个问题? @TroyPoulter 我对 Typescript 不是很熟悉,但使用 String.prototype.matchAll 似乎会产生这个 TS linting 错误。更新了答案和链接的代码框。 啊,是的,就像一个魅力!非常感谢你!所以不允许我再奖励大约 4 小时的赏金,但今天晚些时候会这样做,再次感谢!【参考方案2】:

Tab 组件采用精确值,而不是像 Route 那样的路径,因此 /about-us/:name 中的动态部分 :name 无法被 Tabs 理解。

如果您希望您提到的错误从控制台中消失,我有一个解决方法。 您可以添加另一个不可见的Tab,该Tab 将保存当前pathname 的值,因此您的Tabs 将始终匹配。

首先,添加以下 CSS 类以将额外的 Tab 隐藏到您的 app.css 文件或任何文件中,并确保将其导入

.hidden 
    visibility: hidden;
    position: absolute;
    left: -1000px;
    width: 1px;
    height: 1px;
    overflow: hidden;

然后,添加额外的Tab

import  Link, useLocation  from 'react-router-dom';
import Tabs from '@mui/material/Tabs';
import Tab from '@mui/material/Tab';

const NavBar = () => 
    const location = useLocation();
    const currentTab = location.pathname;
    return (
        <Tabs value=currentTab >
            <Tab label="Home" value="/" to="/" component=Link />
            <Tab label="About Us" value='/about-us' to='/about-us' component=Link />
            <Tab className="hidden" label="*" value=currentTab to=currentTab component=Link />
        </Tabs>
    );


export default NavBar

我正在使用以下版本的库

“反应”:“^17.0.2” “反应域”:“^17.0.2” "@mui/material": "^5.2.1" "react-router-dom": "^5.2.0"

【讨论】:

啊,太好了,我明白你的意思了!我应用了您的建议,是的,确实消除了控制台错误。尽管它还删除了选项卡下方的下划线,但如果可能的话,它会很高兴。此外,这是否可以调整为在子页面上突出显示其中一个选项卡?很高兴它可以自定义匹配,因为某些子页面中可能没有标签名称。一个例子是/our-people/John,我希望About Us 选项卡显示为理想状态。 我认为@Drew Reese 以他的方式回答了你的问题 啊,是的,他在我发表此评论后做了,感谢您的解决方案@Ahmed Hany :)

以上是关于React Material UI - 当没有子项与提供的值匹配时处理导航选项卡的主要内容,如果未能解决你的问题,请参考以下文章

index.js:1375 警告:Material-UI:提供给 Tabs 组件的 `/` 值无效。所有 Tabs 子项都没有此值

当 React Material UI 中的 TextField 中存在值时自定义自动完成 CSS

Material UI 日期选择器 日期格式 React

网格项高度与响应式方形子项不匹配

Material-UI v5 对话框退出淡入淡出动画不适用于 React Router

连续的 Material-UI Snackbars(使用 React-Redux)