React-router-v6 访问 url 参数

zia*_*any 19 reactjs react-router react-router-dom

如何访问 React 组件中的 url 参数?

应用程序.js

<Route path="/question/:id" element={<QuestionView />} />
Run Code Online (Sandbox Code Playgroud)

QuestionView.js

class QuestionView extends React.Component {     
    render() {
          const { questions, users } = this.props;
          const {id} = ??? 
Run Code Online (Sandbox Code Playgroud)

Dre*_*ese 38

问题

在react-router-dom v6中,Route组件不再具有route props(historylocationmatch),当前的解决方案是使用这些组件的React hooks“版本”在正在渲染的组件中使用。不过,React hooks 不能在类组件中使用。

要使用类组件访问匹配参数,您必须转换为函数组件,或者滚动您自己的自定义withRouter高阶组件来注入“路由道具”,就像v5.xwithRouter中的 HOCreact-router-dom所做的那样。

解决方案

我不会介绍如何将类组件转换为函数组件。这是一个自定义withRouterHOC 示例:

const withRouter = WrappedComponent => props => {
  const params = useParams();
  // etc... other react-router-dom v6 hooks

  return (
    <WrappedComponent
      {...props}
      params={params}
      // etc...
    />
  );
};
Run Code Online (Sandbox Code Playgroud)

并用新的 HOC 装饰组件。

export default withRouter(Post);
Run Code Online (Sandbox Code Playgroud)

params这将为类组件注入一个prop。

this.props.params.id
Run Code Online (Sandbox Code Playgroud)


ego*_*xyz 10

withRouter具有通用参数的HOC TypeScript 版本

withRouter.tsx

import { ComponentType } from 'react';
import { useLocation, useNavigate, useParams } from 'react-router-dom';

export interface WithRouterProps<T = ReturnType<typeof useParams>> {
  history: {
    back: () => void;
    goBack: () => void;
    location: ReturnType<typeof useLocation>;
    push: (url: string, state?: any) => void;
  }
  location: ReturnType<typeof useLocation>;
  match: {
    params: T;
  };
  navigate: ReturnType<typeof useNavigate>;
}

export const withRouter = <P extends object>(Component: ComponentType<P>) => {
  return (props: Omit<P, keyof WithRouterProps>) => {
    const location = useLocation();
    const match = { params: useParams() };
    const navigate = useNavigate();

    const history = {
      back: () => navigate(-1),
      goBack: () => navigate(-1),
      location,
      push: (url: string, state?: any) => navigate(url, { state }),
      replace: (url: string, state?: any) => navigate(url, {
        replace: true,
        state
      })
    };

    return (
      <Component
        history={history}
        location={location}
        match={match}
        navigate={navigate}
        {...props as P}
      />
    );
  };
};
Run Code Online (Sandbox Code Playgroud)

MyClass.tsx

import { Component } from 'react';

import { withRouter, WithRouterProps } from './withRouter';

interface Params {
  id: string;
}

type Props = WithRouterProps<Params>;

class MyClass extends Component<Props> {
  render() {
    const { match } = this.props;
    console.log(match.params.id); // with autocomplete
    return <div>MyClass</div>;
  }
}

export default withRouter(MyClass);
Run Code Online (Sandbox Code Playgroud)

  • 你的解决方案确实很吵,我希望这不是使用 TypeScript 和 React Class Component 时最简单的方法。但非常感谢你展示它,它就像一个魅力。 (2认同)