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

Tro*_*zza 6 reactjs react-router material-ui

我的应用程序中有一个导航栏,它使用Material UI v5 - 导航选项卡组件和 React Router v4。因此,当您导航到类似 的内容时/about-us,它会从 url 中读取该内容,然后更改为该选项卡。

问题

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

MUI:value提供给选项卡组件的内容无效。

选项卡的子项均不与“/about-us/john”匹配。

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

您将在我当前方法下面的示例代码部分中看到,我在想是否有办法获得“有效”选项卡 URL 列表,但不确定如何处理如上所述的子页面。

期望的结果

当我导航到类似 的 URL 时/about-us/john,它:

  • 不会抛出上面的错误。
  • [很高兴有] 仍然突出显示该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>
  );
}
Run Code Online (Sandbox Code Playgroud)
// 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>
  );
};
Run Code Online (Sandbox Code Playgroud)

Dre*_*ese 5

问题

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

解决方案

就您的样本而言,NavBar您实际上只需要与任何路由的“根”路径段进行匹配,在本例中为"/""/about-us"。可能有多种方法可以实现此目的,即字符串拆分、REGEX 等...以下示例使用带有捕获组的 REGEX 来获取第一个段。/^(\/[^\/]*)/g从匹配 a 的字符串开头开始匹配"/",并包含所有字符,直到字符串结尾或下一个"/"字符。

console.log([..."/".matchAll(/^(\/[^/]*)/g)][0][1]);
console.log([..."/about-us".matchAll(/^(\/[^/]*)/g)][0][1]);
console.log([..."/about-us/john".matchAll(/^(\/[^/]*)/g)][0][1]);
Run Code Online (Sandbox Code Playgroud)

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>
  );
};
Run Code Online (Sandbox Code Playgroud)

编辑react-material-ui-handle-nav-tabs-when-no-children-match-the-provided-value

在此输入图像描述

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

<Switch>
  <Route path="/about-us/:name">
    <AboutUsDetail />
  </Route>
  <Route path="/about-us">
    <AboutUs />
  </Route>
  <Route path="/">
    <Home />
  </Route>
</Switch>
Run Code Online (Sandbox Code Playgroud)

  • @TroyPoulter 我对 Typescript 不太熟悉,但使用 `String.prototype.matchAll` 似乎*不会*产生这个 TS linting 错误。更新了答案和链接的代码和框。 (2认同)