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

Posted

技术标签:

【中文标题】类组件内的 react-router-dom useParams()【英文标题】:react-router-dom useParams() inside class component 【发布时间】: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 中的函数:***.com/a/70251443/624533 【参考方案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 挂在你的组件中。

【讨论】:

...这里是一个如何做到的例子:Edit react-router-v5-to-v6-compatibility【参考方案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 循环。我用钥匙阻止了它。

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

参考:

using useParams state inside function preventing loop from 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。

以上是关于类组件内的 react-router-dom useParams()的主要内容,如果未能解决你的问题,请参考以下文章

使用 react-router-dom 时功能组件消失

React中使用路由进行父子组件的通信

React redirect - react-router-dom 上的重定向组件

导入使用 React-Router-Dom 的自定义模块组件时出现问题

使用 react-router-dom 在 Route 中添加组件作为道具

React-router-dom 渲染道具没有返回任何组件