react-router-dom useParams() 在类组件中



我正在尝试加载基于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.

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

版本 <= 5:

您可以使用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);

就这么简单!

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);

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

class TaskDetail extends React.Component {
componentDidMount() {
const { id } = this.props.params;
// ...
}
}
export default (props) => (
<TaskDetail
{...props}
params={useParams()}
/>
);

但是,正如@michael-mayo所说,我希望这就是withRouter已经在表现的。

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

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.Components 调用像 "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

在 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} />;
};

然后从 HOC 导出组件,并将组件作为参数提供。 如下所示:

export default withRouter(YourComponentName);

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

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);

SmujMaiku 是严谨的!!他的回答非常有效。这就是今天与反应路由器 v6 一起工作的方式

enter code here

import React ,{Component} from 'react'
import {  useParams } from "react-router-dom";
import PokeDescription from '../components/PokeDescription'
class PokeInfoConteiner extends Component{
render(){

let urlPokemon= "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/"


const {idPokemon} = this.props.params 
console.log(idPokemon)
return(

<div>
<PokeDescription pokeImage={`${urlPokemon}${idPokemon}.png?raw=true`}/>
<p>{}</p>

</div>
)
}

}

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

在 React Router V6 中

import React, {Component} from 'react';
import {useParams} from 'react-router-dom';
/* This is a higher order component that 
*  inject a special prop   to our component.
*/ 
function withRouter(Component) {
function ComponentWithRouter(props) {
let params = useParams()
return <Component {...props} params={params} />
}
return ComponentWithRouter
}
class TaskDetail extends React.Component {
state={
id : ""
}
componentDidMount() {
this.setState({
id : this.props.params.id
})
}
static getDerivedStateFromProps(nextProps) {
return {
id : nextProps.params.id
}
}
fetchData = id => {
// ...
};
render() {
return <div>Yo</div>;
}
}

const HOCTaskDetail = withRouter(TaskDetail);
export default HOCTaskDetail;

React Route v6

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

在这里我使用的是useState,useEffect,useParams,axios。

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;

注意:我面临使用效果循环。我用钥匙阻止了它。

希望:这可能会帮助某人!

参考:

  • 使用 useParams
  • 函数内部状态
  • 防止循环使用效果

在 react-router-dom v6 中,没有像withRouter这样的钩子,因此我给你的建议是将基于类的组件转换为功能组件,以便在组件中使用useParams钩子,否则你可以创建一个高阶组件来传递基于类的组件。

如您所知,useParams()是react-router-dom的钩子。 你不能在 componentDidMount() 或 useEffect() 中使用它,因为它们都是在 React 生命周期的挂载阶段(即组件渲染之后)调用的方法。 您有一个解决方案: 在 componentDidMount() 外部创建或定义另一个函数以定义 useParams,然后在 componentDidMount 中调用它。 知道一切都会好起来的。

这是我的工作示例。 :)

import React, { Component } from "react";
import { useParams } from "react-router-dom";
function withParams(Component) {
return (props) => <Component {...props} params={useParams()} />;
}
class ProductDetails extends Component {
handleSave = () => {
// Navigate to /products
};
render() {
return (
<div>
<h1>Product Details - {this.props.params.id}</h1>
<button onClick={this.handleSave}>Save</button>
</div>
);
}
}
export default withParams(ProductDetails);

钩子只适用于功能组件, 您必须使该占用器成为功能组件

通过创建包装函数修复

我需要使用 react-router-dom v6 将参数从索引传递到我的 SaxjaxApp.js.js。 在 v6 中,Switch已更改为Routes

我通过使用包装函数在 20 后遵循 Mohamed MAZEK 的想法,让 useParams 与类组件一起工作。

当 url 可用时,我需要访问它的sessionId部分。

即在localhost:3000/shared/123XYZId我需要123XYZId部分。

记下这一行:<Route path="/shared/:sessionId" element={<SaxjaxAppWrapper />} />在下面的索引.js。

:sessionId表示useParams有一个名为sessionId的属性,可以通过以下方式访问:

const {sessionId} = useParams()功能组件。

在我的索引.js文件中,我这样做了:

import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import "./styles/style.scss";
import SaxjaxAppWrapper from "SaxjaxAppWrapper";
import SaxjaxApp from "./SaxjaxApp";
const container = document.getElementById("root");
const root = ReactDOM.createRoot(container);
//INFO: to learn about react-roue-dom v6 https://reactrouter.com/en/v6.3.0/upgrading/v5
root.render(
// <React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/shared/:sessionId" element={<SaxjaxAppWrapper />} />
<Route path="/" element={<SaxjaxApp />} />
</Routes>
</BrowserRouter>
// </React.StrictMode>
);

这一行<Route path="/shared/:sessionId" element={<SaxjaxAppWrapper />} />调用我的包装函数,而默认路径/只调用类组件。

我必须创建一个单独的文件来保存我不知道为什么的包装功能:

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

function SaxjaxAppWrapper() {
//I use the params here and store them to pass as props 
let { sessionId } = useParams();
return (
//I pass the sessionId from the url params as a prop to my SaxjaxApp class component here
<SaxjaxApp sessionId={sessionId} />
);
}

export default SaxjaxAppWrapper;

我的类组件:

import React, { Component } from "react";
import "./styles/style.scss";
class SaxjaxApp extends Component {
state = {
octave: 4,
};
constructor(props) {
super(props);
//... initialise stuff
}
//... a lot of methods
render() {
//Access the param here
const { sessionId } = this.props;
<>
<div>
keybordId={sessionId ? sessionId : "no id was passed"}
</div>
</>
);
}
}
export default SaxjaxApp;

错误,因为:

  • 仅在功能组件中使用的钩子
  • 在 id 值
  • 的减速中使用 const 替代使用 let,因为您不需要更改 id 值

更正的代码:

import React, { useEffect } from "react";
import { useParams } from "react-router-dom";
function TaskDetail() {
const { id } = useParams();
useEffect(() => {
fetchData(id);
}, [id]);
const fetchData = (id) => {
// ... Implement data fetching logic here
};
return <div>Yo</div>;
}
export default TaskDetail;

最新更新