英文:
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;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论