【问题标题】:react-router-dom useParams() inside class component类组件内的 react-router-dom useParams()
【发布时间】:2020-02-21 05:32:00
【问题描述】:

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

我的路由看起来像/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;

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

Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

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

【问题讨论】:

  • 钩子在基于类的组件中不起作用
  • @Dupocas 好的,这是有道理的。您会建议什么,将类重写为函数或使用类并尝试以其他方式获取 url 参数?
  • 两个有效的选择。您可以发布useParams 的代码吗?也许把它变成HOC
  • 谁能评论一下为什么这仅限于功能组件?我已经使用 React 大概 8 个月了,像这样的事情对我来说仍然是一个常规的“陷阱”,很想更好地理解它。
  • React Route v6 中的函数:stackoverflow.com/a/70251443/624533

标签: reactjs react-router


【解决方案1】:

您可以使用withRouter 来完成此操作。只需将导出的分类组件包装在withRouter 中,然后您可以使用this.props.match.params.id 来获取参数,而不是使用useParams()。您还可以使用withRouter 获取任何locationmatchhistory 信息。都是在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);

就这么简单!

【讨论】:

  • 在 react router dom v6 中使用 withRouter 时出现错误:Attempted import error: 'withRouter' is not exported from 'react-router-dom'
  • 是的,看起来 v6 不再使用它了。您仍然可以从react-router 导入它。我将更新我的答案以反映这一点
  • react-router 也不包含withRouter。我得到了同样的错误结果
  • 这里是使用它的docs。也许这会有所帮助
【解决方案2】:

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

props.match.params.yourParams

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

以下是文档中的一个示例,它破坏了参数中的道具。

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

【讨论】:

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

You can not call a hook 例如来自 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;

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

<Switch>
  <Route path="/task/:id" component={GetId} />
</Switch>

那么你就可以从你的 react 组件中的 props 中获取 id

this.props.taskId

【讨论】:

  • 一个衬里 RouteComponent 有效,而不是 &lt;Route&gt;code&lt;/Route&gt; 无效,为什么会这样?
  • 在import语句中应该是{useParams}而不是useParams。
【解决方案4】:

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

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

export default (props) => (
    <TaskDetail
        {...props}
        params={useParams()}
    />
);

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

【讨论】:

    【解决方案5】:

    React Route v5

    可以使用withRouterqueryString 将查询参数作为JSON 读取和处理,如下所示:

    import React from "react";
    import { withRouter } from "react-router";
    import queryString from 'query-string';
        
    class MyComponent extends React.Component {
        componentDidMount() {
            const params = queryString.parse(this.props.location.search);
            console.log('Do something with it', params);
        }
    
        render() {
            return <div>Hi!</div>;
        }
    }
    
    export default withRouter(MyComponent);
    

    【讨论】:

      【解决方案6】:

      在 react-router-dom v6 中,没有诸如 withRouter 之类的钩子,因此我的建议是将基于类的组件转换为功能组件以使用 useParams 挂在你的组件中。

      【讨论】:

      【解决方案7】:

      React Route v6

      我的朋友们,我试图在课堂上使用,但我没有找到任何关于它的文档。因此,经过数小时的搜索和努力,这就是(功能)。现在(即当我写这篇文章时)关于 v6 的资源有限。但是

      这里我使用的是 useStateuseEffectuseParamsaxios

      import React, { useState, useEffect } from 'react';
      import { useParams } from 'react-router-dom';
      import axios from 'axios';
      
      const Post = () => {
          let { post_id } = useParams();
          const [posts, setPosts] = useState({ post: null, countSecrets: 0, ui: '' });
      
          useEffect(() => {
              if (posts.countSecrets === 0) {
                  const doAxe = (a) => {
                      axios.get('https://jsonplaceholder.typicode.com/posts/' + post_id)
                          .then((res) => {
                              setPosts(s => ({ ...s, value: res.data }));
                              doUI(res.data)
                              // console.log(res.data)
                          });
                  }
                  setPosts(s => ({ ...s, countSecrets: s.countSecrets + 1 }));
                  doAxe()
              }
          }, [posts, post_id]);
          let doUI = (x) => {
              // console.log('x' + x.title)
              const finalPost = (x !== null) ? (
                  <div className="post">
                      <h4 className="center">{x.title}</h4>
                      <p>{x.body}</p>
                  </div>
              ) : (
                  <div className="center">Loading posts...</div>
              );
              setPosts(s => ({ ...s, ui: finalPost }));
          }
          return (
              <div className="container">
                  {posts.ui}
              </div>
          );
      }
      
      export default Post;
      

      注意: 我遇到了 useEffect 循环。我用钥匙阻止了它。

      希望:这可能对某人有所帮助!

      参考:

      【讨论】:

        【解决方案8】:
        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);
        

        【讨论】:

        • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
        猜你喜欢
        • 2022-12-10
        • 2021-05-10
        • 2023-02-06
        • 2022-01-12
        • 2021-05-06
        • 2023-02-01
        • 2022-12-22
        • 2022-01-10
        • 2022-06-16
        相关资源
        最近更新 更多