如何在 React Router v6 中正确获取当前路径名?
How to get the current pathname correctly in React Router v6?
Full example in codesandbox
我正在使用一个名为 Material-UI, to build up my app layout. I am using its <ListItemButton>
component inside the sidenav of my app. Now. this component <ListItemButton>
is not a link, its a button. but it has some styles, you can see how it looks here, click me 的库。这个组件接受一个 component
道具,这个 component
道具的作用是它基本上允许你在里面渲染一些东西,例如,我可以给它 <div/>
,我可以给它<a/>
我可以给它<b/>
等等,但我也可以给它一个 React 组件。这就是我在这里所做的。我给它 React 路由器 <NavLink>
组件。
现在。这很简单,只需给它 <NavLink>
组件,它就会开始工作。但是,不幸的是,它不允许您将 <NavLink>
写成 <NavLink>
,您必须将它写成 NavLink
并且不带括号,因此,我不能向它传递任何参数。
幸运的是,这个 Material-UI 的工作方式是,当它在其组件之一(例如 <ListItemButton>
组件中看到它不理解的道具时,它会自动将该道具传递给子组件。所以在我们的例子中,如果我们写了一个不在 <ListItemButton>
文档中的道具,它将把它传递给 NavLink
组件。
因此,我们可以传递 to
属性。如下:
<ListItemButton to="/users" component={NavLink}>
到目前为止一切顺利。我们必须做的最后一件事是确保只要搜索栏中的 link 与指定的 NavLink 相匹配,ListItemButton 组件就会突出显示路径。
好消息是 <ListItemButton>
有一个预定义的属性,使它在屏幕上看起来像 selected,所以它突出显示得更暗一些。这个道具叫做 selected
道具,它接受一个布尔值,(true 或 false)。所以:
我们怎样才能做到这一点?我们可以通过比较搜索栏中的 URL 是否与我们在 to
prop.
中指定的路径相匹配来实现
至此就介绍了为什么我想找出当前使用的路径。
那么问题来了:
据我所知,唯一的方法是比较当前访问的 link 是否与 NavLink 或Link 组件,方法如下:
<ListItemButton to="/users" component={NavLink} selected={pathname === "/users"}>
我知道这个问题之前有人回答过,我看到有人提到这个问题的方法是使用 useLocation()
钩子,他们说你可以这样做:然后做比较:
const { pathname } = useLocation()
然而,这并不总是有效,例如,如果用户访问了以下 links,ListItemButton 组件 Not 将被突出显示 ( selected):
- http://example.com/users ✅ 有效
- http://example.com/users/ ❌不起作用
- http://example.com/users// ❌不起作用
- http://example.com/users/// ❌不起作用
你可能会说,好吧,简单地使用.includes()
比较如下:
<ListItemButton to="/users" component={NavLink} selected={pathname.includes("/users")}>
但请记住,如果您在 sidenav 中有其他路线,则不应这样做,例如:
- 管理用户 (/users)
- 创建用户 (/users/create)
因为如果您使用 .includes()
方法进行比较,您最终会突出显示 (selecting) NavLinks (ListItemButton).
所以,现在,有没有内置的React Router Hook,或者方法可以正确获取路由名称,我在<BrowserRouter>
中定义的确切名称我的index.js 文件?
& 谢谢你
我明白了,如果我对您的 post 理解正确的话,您正在尝试设置按钮的样式而不是真正的 NavLink
组件。我认为您可能正在寻找 useMatch
挂钩。
Returns true if the URL for the given "to" value matches the current
URL. This is useful for components that need to know "active" state, e.g. <NavLink>
.
import { useMatch } from 'react-router-dom';
...
const isUserRoute = useMatch("/user");
...
<ListItemButton
to="/users"
component={NavLink}
selected={isUserRoute}
>
...
</ListItemButton>
更新
要为每个 ListItemButton
使用 useMatch
挂钩,我建议将 ListItemButton
分解到它自己的组件中。
示例:
const LinkButton = ({ children, to }) => {
const selected = useMatch(to);
return (
<ListItemButton
component={NavLink}
to={to}
selected={selected}
>
{children}
</ListItemButton>
);
};
在 UI 中使用 LinkButton
而不是 ListItemButton
。
<div>
{listItems.map((item) => (
<LinkButton key={item.label} to={item.path}>
{item.label}
</LinkButton>
))}
</div>
如果您希望将路径匹配本地化到父组件,请导入并使用 react-router-dom
中的 useLocation
挂钩和 matchPath
实用程序。
示例:
import { useLocation, matchPath } from 'react-router-dom';
...
const { pathname } = useLocation();
...
<div>
{listItems.map((item) => (
<ListItemButton
component={NavLink}
to={item.path}
selected={matchPath(item.path, pathname)}
>
{item.label}
</ListItemButton>
))}
</div>
Full example in codesandbox
我正在使用一个名为 Material-UI, to build up my app layout. I am using its <ListItemButton>
component inside the sidenav of my app. Now. this component <ListItemButton>
is not a link, its a button. but it has some styles, you can see how it looks here, click me 的库。这个组件接受一个 component
道具,这个 component
道具的作用是它基本上允许你在里面渲染一些东西,例如,我可以给它 <div/>
,我可以给它<a/>
我可以给它<b/>
等等,但我也可以给它一个 React 组件。这就是我在这里所做的。我给它 React 路由器 <NavLink>
组件。
现在。这很简单,只需给它 <NavLink>
组件,它就会开始工作。但是,不幸的是,它不允许您将 <NavLink>
写成 <NavLink>
,您必须将它写成 NavLink
并且不带括号,因此,我不能向它传递任何参数。
幸运的是,这个 Material-UI 的工作方式是,当它在其组件之一(例如 <ListItemButton>
组件中看到它不理解的道具时,它会自动将该道具传递给子组件。所以在我们的例子中,如果我们写了一个不在 <ListItemButton>
文档中的道具,它将把它传递给 NavLink
组件。
因此,我们可以传递 to
属性。如下:
<ListItemButton to="/users" component={NavLink}>
到目前为止一切顺利。我们必须做的最后一件事是确保只要搜索栏中的 link 与指定的 NavLink 相匹配,ListItemButton 组件就会突出显示路径。
好消息是 <ListItemButton>
有一个预定义的属性,使它在屏幕上看起来像 selected,所以它突出显示得更暗一些。这个道具叫做 selected
道具,它接受一个布尔值,(true 或 false)。所以:
我们怎样才能做到这一点?我们可以通过比较搜索栏中的 URL 是否与我们在 to
prop.
至此就介绍了为什么我想找出当前使用的路径。
那么问题来了:
据我所知,唯一的方法是比较当前访问的 link 是否与 NavLink 或Link 组件,方法如下:
<ListItemButton to="/users" component={NavLink} selected={pathname === "/users"}>
我知道这个问题之前有人回答过,我看到有人提到这个问题的方法是使用 useLocation()
钩子,他们说你可以这样做:然后做比较:
const { pathname } = useLocation()
然而,这并不总是有效,例如,如果用户访问了以下 links,ListItemButton 组件 Not 将被突出显示 ( selected):
- http://example.com/users ✅ 有效
- http://example.com/users/ ❌不起作用
- http://example.com/users// ❌不起作用
- http://example.com/users/// ❌不起作用
你可能会说,好吧,简单地使用.includes()
比较如下:
<ListItemButton to="/users" component={NavLink} selected={pathname.includes("/users")}>
但请记住,如果您在 sidenav 中有其他路线,则不应这样做,例如:
- 管理用户 (/users)
- 创建用户 (/users/create)
因为如果您使用 .includes()
方法进行比较,您最终会突出显示 (selecting) NavLinks (ListItemButton).
所以,现在,有没有内置的React Router Hook,或者方法可以正确获取路由名称,我在<BrowserRouter>
中定义的确切名称我的index.js 文件?
& 谢谢你
我明白了,如果我对您的 post 理解正确的话,您正在尝试设置按钮的样式而不是真正的 NavLink
组件。我认为您可能正在寻找 useMatch
挂钩。
Returns true if the URL for the given "to" value matches the current URL. This is useful for components that need to know "active" state, e.g.
<NavLink>
.
import { useMatch } from 'react-router-dom';
...
const isUserRoute = useMatch("/user");
...
<ListItemButton
to="/users"
component={NavLink}
selected={isUserRoute}
>
...
</ListItemButton>
更新
要为每个 ListItemButton
使用 useMatch
挂钩,我建议将 ListItemButton
分解到它自己的组件中。
示例:
const LinkButton = ({ children, to }) => {
const selected = useMatch(to);
return (
<ListItemButton
component={NavLink}
to={to}
selected={selected}
>
{children}
</ListItemButton>
);
};
在 UI 中使用 LinkButton
而不是 ListItemButton
。
<div>
{listItems.map((item) => (
<LinkButton key={item.label} to={item.path}>
{item.label}
</LinkButton>
))}
</div>
如果您希望将路径匹配本地化到父组件,请导入并使用 react-router-dom
中的 useLocation
挂钩和 matchPath
实用程序。
示例:
import { useLocation, matchPath } from 'react-router-dom';
...
const { pathname } = useLocation();
...
<div>
{listItems.map((item) => (
<ListItemButton
component={NavLink}
to={item.path}
selected={matchPath(item.path, pathname)}
>
{item.label}
</ListItemButton>
))}
</div>