英文:
useMatch() not working with React Router v6
问题
I just updated my project to use react-router-dom
v6 from v5 and the components that previously used props.match
are no longer working using useMatch
.
In Firefox I get the error - Can't access property "path", pattern is undefined.
In Chrome I get the error - Cannot read properties of undefined (reading 'path').
The components look something like this:
import React, { useEffect, useState } from 'react';
import { Route, Routes, useMatch, useParams } from "react-router-dom";
import { businessDetail } from "../../../../redux/actions/business";
import {
BusinessSettingTeamButtons,
BusinessSettingTeamBody
} from "./BusinessPageTeam";
function BusinessPage (props) {
const params = useParams()
const { url, pathname } = useMatch();
const [slug, setSlug] = useState(params.businessSlug);
// ADDED TO THE EDIT
const businessSettingTeamButtons = <BusinessSettingTeamButtons
url={url}
setSettings={setSettings}/>;
useEffect(() => {
const loadBusiness = () => {
props.businessDetail(slug);
}
loadBusiness()
}, [props.businessDetail])
const bodies =
<div>
<Routes>
<Route path={`${pathname}`}>
{businessSettingProfileBody}
</Route>
<Route path={`${pathname}/team`}>
{businessSettingTeamBody}
</Route>
<Route path={`${pathname}/settings`}>
{businessSettingBody}
</Route>
</Routes>
</div>
return (
<div>
{bodies}
</div>
)
}
function mapStateToProps(state) {
return {
business: state.business,
}
}
export default connect(mapStateToProps, { businessDetail })(BusinessPage);
Routes
was previously named Switch
and pathname
was previously named path
.
Child component:
export function BusinessSettingTeamButtons (props) {
return (
<nav>
<Link
className="btn btn-link"
onClick={() => props.setSettings('profile')}
to={`${props.url}`}
>
Profile
</Link>
<Link
className="btn btn-primary"
onClick={() => props.setSettings('team')}
to={`${props.url}/team`}
>
Team
</Link>
<Link
className="btn btn-link"
onClick={() => props.setSettings('settings')}
to={`${props.url}/settings`}
>
Settings
</Link>
</nav>
);
}
英文:
I just updated my project to use react-router-dom
v6 from v5 and the components that previously used props.match
are no longer working using useMatch
.
In Firefox I get the error - Can't access property "path", pattern is undefined
In Chrome I get the error - Cannot read properties of undefined (reading 'path')
The components look something like this:
import React, { useEffect, useState } from 'react';
import { Route, Routes, useMatch, useParams } from "react-router-dom";
import { businessDetail } from "../../../../redux/actions/business";
import {
BusinessSettingTeamButtons,
BusinessSettingTeamBody
} from "./BusinessPageTeam";
function BusinessPage (props) {
const params = useParams()
const { url, pathname } = useMatch();
const [slug, setSlug] = useState(params.businessSlug);
// ADDED TO THE EDIT
const businessSettingTeamButtons = <BusinessSettingTeamButtons
url={url}
setSettings={setSettings}/>
useEffect(() => {
const loadBusiness = () => {
props.businessDetail(slug);
}
loadBusiness()
}, [props.businessDetail])
const bodies =
<div>
<Routes>
<Route path={`${pathname}`}>
{businessSettingProfileBody}
</Route>
<Route path={`${pathname}/team`}>
{businessSettingTeamBody}
</Route>
<Route path={`${pathname}/settings`}>
{businessSettingBody}
</Route>
</Routes>
</div>
return (
<div>
{bodies}
</div>
)
}
function mapStateToProps(state) {
return {
business: state.business,
}
}
export default connect(mapStateToProps, { businessDetail })(BusinessPage);
Routes
was previously named Switch
and pathname
was previously named path
.
Child component:
export function BusinessSettingTeamButtons (props) {
return (
<nav>
<Link
className="btn btn-link"
onClick={() => props.setSettings('profile')}
to={`${props.url}`}
>
Profile
</Link>
<Link
className="btn btn-primary"
onClick={() => props.setSettings('team')}
to={`${props.url}/team`}
>
Team
</Link>
<Link
className="btn btn-link"
onClick={() => props.setSettings('settings')}
to={`${props.url}/settings`}
>
Settings
</Link>
</nav>
);
}
答案1
得分: 1
The useMatch
hook接受一个用于路由匹配的必需路径模式。
请参考useMatch
declare function useMatch<ParamKey extends ParamParseKey<Path>, Path extends string>(
pattern: PathPattern<Path> | Path // <--- 必需参数!
): PathMatch<ParamKey> | null;
但是,使用react-router-dom@6
的好消息是,如果你只是渲染后代路由,你不需要实现这一部分。Routes
组件构建相对于父路由的后代路由,因此手动获取父路由的url
和pathname
是完全不必要的,你只需指定相对路径。
Route
组件也不接受子内容,Route
组件的唯一有效子级是嵌套路由的情况下的另一个Route
组件。将路由内容放在Route
组件的element
属性上,该属性接受React.ReactNode
,即JSX值。请确保businessSettingProfileBody
,businessSettingTeamBody
和businessSettingBody
都是JSX值(如果它们不是,那么UI的这一部分可能需要稍作调整)。
import React, { useEffect } from 'react';
import { Route, Routes, useParams } from "react-router-dom";
import { useDispatch, useSelector } from 'react-redux';
import { businessDetail } from "../../../../redux/actions/business";
function BusinessPage () {
const dispatch = useDispatch();
const { businessSlug } = useParams();
const business = useSelector(state => state.business); // 这在哪里使用?
useEffect(() => {
// 组件挂载/初始渲染时分发
dispatch(businessDetail(businessSlug));
}, []);
return (
<div>
<Routes>
<Route path="/" element={businessSettingProfileBody} />
<Route path="/team" element={businessSettingTeamBody} />
<Route path="/settings" element={businessSettingBody} />
</Routes>
</div>
)
}
export default BusinessPage;
英文:
The useMatch
hook takes a required path pattern for route matching.
See useMatch
> declare function useMatch<
> ParamKey extends ParamParseKey<Path>,
> Path extends string
> >(
> pattern: PathPattern<Path> | Path // <-- required argument!
> ): PathMatch<ParamKey> | null;
But the good news with react-router-dom@6
is that you don't need to implement this part if all you are doing is rendering descendent routes. The Routes
component builds descendent routes relative to the parent routes, so it's completely unnecessary to get the url
and pathname
of the parent route manually, you can just specify the relative paths.
The Route
component also doesn't take children content, the only valid child of a Route
component is another Route
component in the case of nested routing. Place the routed content on the Route
component's element
prop, which takes a React.ReactNode
, a.k.a. JSX value. Be sure that businessSettingProfileBody
, businessSettingTeamBody
, and businessSettingBody
are JSX values (JSX literals are ok IIRC). If they are not then this part of the UI might need to be tweaked a little.
import React, { useEffect } from 'react';
import { Route, Routes, useParams } from "react-router-dom";
import { useDispatch, useSelector } from 'react-redux';
import { businessDetail } from "../../../../redux/actions/business";
function BusinessPage () {
const dispatch = useDispatch();
const { businessSlug } = useParams();
const business = useSelector(state => state.business); // where is this used?
useEffect(() => {
// dispatch on component mount/initial render
dispatch(businessDetail(businessSlug));
}, []);
return (
<div>
<Routes>
<Route path="/" element={businessSettingProfileBody} />
<Route path="/team" element={businessSettingTeamBody} />
<Route path="/settings" element={businessSettingBody} />
</Routes>
</div>
)
}
export default BusinessPage;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论