类组件内部的react-router-dom useParams()

Jor*_*rre 1 reactjs react-router

我正在尝试基于应获取URL参数(id)的react-router-dom路由加载详细信息视图,并使用该参数进一步填充组件。

我的路线看起来很像,/task/:id并且我的组件加载正常,直到我尝试像这样从URL抓取:id为止:

    import React from "react";
    import { useParams } from "react-router-dom";

    class TaskDetail extends React.Component {
        componentDidMount() {
            let { id } = useParams();
            this.fetchData(id);
        }

        fetchData = id => {
            // ...
        };

        render() {
            return <div>Yo</div>;
        }
    }

export default TaskDetail;
Run Code Online (Sandbox Code Playgroud)

这会触发以下错误,我不确定在哪里正确实现useParams()。

Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
Run Code Online (Sandbox Code Playgroud)

该文档仅显示基于功能组件的示例,而不是基于类的示例。

感谢您的帮助,我是新来的人。

小智 30

import React, { Component } from "react";
import { useParams } from "react-router-dom";

function withParams(Component) {
  return props => <Component {...props} params={useParams()} />;
}


class TaskDetail extends React.Component {
    componentDidMount() {
        let { id } = this.props.params;
        this.fetchData(id);
    }

    fetchData = id => {
        // ...
    };

    render() {
        return <div>Yo</div>;
    }
}

export default withParams(TaskDetail);
Run Code Online (Sandbox Code Playgroud)

  • 真的对我很有帮助,将类组件包装在函数中以作为自定义 HOC 工作是关键 (2认同)

Smu*_*iku 19

由于钩子不适用于基于类的组件,因此您可以将其包装在函数中并传递属性:

class TaskDetail extends React.Component {
    componentDidMount() {
        const { id } = this.props.params;
        // ...
    }
}

export default (props) => (
    <TaskDetail
        {...props}
        params={useParams()}
    />
);
Run Code Online (Sandbox Code Playgroud)

但是,就像 @michael-mayo 所说,我希望这就是withRouter已经在执行的操作。

  • 谢谢你 - `withRouter` 不再是一个选项,因为它已从 React-router ^6 中删除。该解决方案有效,并在我需要弃用基于大型类的组件之前为我提供了更多时间。 (4认同)

小智 9

参数通过匹配对象上的道具传递。

props.match.params.yourParams
Run Code Online (Sandbox Code Playgroud)

来源:https : //redux.js.org/advanced/usage-with-react-router

这是文档中破坏参数中的道具的示例。

const App = ({ match: { params } }) => {
  return (
    <div>
      <AddTodo />
      <VisibleTodoList filter={params.filter || 'SHOW_ALL'} />
      <Footer />
    </div>
  )
}
Run Code Online (Sandbox Code Playgroud)

  • 这似乎是一个非常干净的解决方案,可以避免钩子,但是有什么警告吗?为什么react-router文档没有提到这个作为替代方案,而只在文档中显示hooks示例? (2认同)

小智 6

您可以withRouter用来完成此任务。只需将导出的分类组件包装在其中withRouter,然后就可以使用this.props.match.params.id来获取参数,而不必使用useParams()。您还可以得到任何locationmatchhistory通过使用信息withRouter。他们都被传进来this.props

使用您的示例,它看起来像这样:

    import React from "react";
    import { withRouter } from "react-router";

    class TaskDetail extends React.Component {
        componentDidMount() {
            const id = this.props.match.params.id;
            this.fetchData(id);
        }

        fetchData = id => {
            // ...
        };

        render() {
            return <div>Yo</div>;
        }
    }

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

就那么简单!

  • `react-router` 也不包含 `withRouter` 。我得到了相同的错误结果 (4认同)
  • 在 React router dom v6 中使用 withRouter 时出现错误:“尝试导入错误:‘withRouter’未从‘react-router-dom’导出” (3认同)
  • 这不再是一个有效的解决方案 - withRouter 在 `react-router` 6 中不可用。 (2认同)

Ric*_*Web 6

您不能从 React.Component调用诸如“useParams()”之类的钩子。

如果您想使用钩子并拥有现有的react.component,最简单的方法是创建一个函数,然后从该函数调用React.Component并传递参数。

import React from 'react';
import useParams from "react-router-dom";

import TaskDetail from './TaskDetail';

function GetId() {

    const { id } = useParams();
    console.log(id);

    return (
        <div>
            <TaskDetail taskId={id} />
        </div>
    );
}

export default GetId;
Run Code Online (Sandbox Code Playgroud)

你的切换路线仍然是这样的

<Switch>
  <Route path="/task/:id" component={GetId} />
</Switch>
Run Code Online (Sandbox Code Playgroud)

然后你就可以从你的反应组件中的 props 中获取 id

this.props.taskId
Run Code Online (Sandbox Code Playgroud)


小智 5

在react-router-dom-v6中,您可以轻松地在功能组件中使用useParams(),但是当它到达类组件时,您必须创建HOC(高阶组件),因为钩子不支持类组件:

import { useNavigate, useParams } from "react-router-dom";

export const withRouter = (WrappedComponent) => (props) => {
  const params = useParams();
  const navigate = useNavigate();

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

然后从 HOC 导出您的组件并将您的组件作为参数提供。像下面这样:

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

之后,您可以轻松访问 url id,this.props.params.id并且可以使用导航到其他组件this.props.navigate("/YourPath")