useMatch()在React Router v6中不起作用。

huangapple go评论75阅读模式
英文:

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 &#39;react&#39;;
import { Route, Routes, useMatch, useParams } from &quot;react-router-dom&quot;;
import { businessDetail } from &quot;../../../../redux/actions/business&quot;;
import {
  BusinessSettingTeamButtons,
  BusinessSettingTeamBody
} from &quot;./BusinessPageTeam&quot;;

function BusinessPage (props) {
  const params = useParams()
  const { url, pathname } = useMatch();

  const [slug, setSlug] = useState(params.businessSlug);

  // ADDED TO THE EDIT
  const businessSettingTeamButtons = &lt;BusinessSettingTeamButtons
      url={url}
      setSettings={setSettings}/&gt;

  useEffect(() =&gt; {
    const loadBusiness = () =&gt; {
      props.businessDetail(slug);
    }
    loadBusiness()
  }, [props.businessDetail])

  const bodies =
    &lt;div&gt;
      &lt;Routes&gt;
        &lt;Route path={`${pathname}`}&gt;
          {businessSettingProfileBody}
        &lt;/Route&gt;
        &lt;Route path={`${pathname}/team`}&gt;
          {businessSettingTeamBody}
        &lt;/Route&gt;
        &lt;Route path={`${pathname}/settings`}&gt;
          {businessSettingBody}
        &lt;/Route&gt;
      &lt;/Routes&gt;
    &lt;/div&gt;

  return (
    &lt;div&gt;
      {bodies}
    &lt;/div&gt;
  )
}

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 (
    &lt;nav&gt;
      &lt;Link
        className=&quot;btn btn-link&quot;
        onClick={() =&gt; props.setSettings(&#39;profile&#39;)}
        to={`${props.url}`}
      &gt;
        Profile
      &lt;/Link&gt;
      &lt;Link
        className=&quot;btn btn-primary&quot;
        onClick={() =&gt; props.setSettings(&#39;team&#39;)}
        to={`${props.url}/team`}
      &gt;
        Team
      &lt;/Link&gt;
      &lt;Link
        className=&quot;btn btn-link&quot;
        onClick={() =&gt; props.setSettings(&#39;settings&#39;)}
        to={`${props.url}/settings`}
      &gt;
        Settings
      &lt;/Link&gt;
    &lt;/nav&gt;
  );
}

答案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组件构建相对于父路由的后代路由,因此手动获取父路由的urlpathname是完全不必要的,你只需指定相对路径。

Route组件也不接受子内容,Route组件的唯一有效子级是嵌套路由的情况下的另一个Route组件。将路由内容放在Route组件的element属性上,该属性接受React.ReactNode,即JSX值。请确保businessSettingProfileBodybusinessSettingTeamBodybusinessSettingBody都是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 &#39;react&#39;;
import { Route, Routes, useParams } from &quot;react-router-dom&quot;;
import { useDispatch, useSelector } from &#39;react-redux&#39;;
import { businessDetail } from &quot;../../../../redux/actions/business&quot;;

function BusinessPage () {
  const dispatch = useDispatch();

  const { businessSlug } = useParams();

  const business = useSelector(state =&gt; state.business); // where is this used?

  useEffect(() =&gt; {
    // dispatch on component mount/initial render
    dispatch(businessDetail(businessSlug));
  }, []);

  return (
    &lt;div&gt;
      &lt;Routes&gt;
        &lt;Route path=&quot;/&quot; element={businessSettingProfileBody} /&gt;
        &lt;Route path=&quot;/team&quot; element={businessSettingTeamBody} /&gt;
        &lt;Route path=&quot;/settings&quot; element={businessSettingBody} /&gt;
      &lt;/Routes&gt;
    &lt;/div&gt;
  )
}

export default BusinessPage;

huangapple
  • 本文由 发表于 2023年2月24日 03:24:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/75549435.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定