簡體   English   中英

class 組件內的 react-router-dom useParams()

[英]react-router-dom useParams() inside class component

我正在嘗試加載基於 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.

文檔僅顯示基於功能組件的示例,而不是基於 class 的示例。

版本 <= 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 的組件,您可以將其包裝在 function 中並傳遞屬性:

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

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

但是,就像@michael-mayo 所說,我希望這就是withRouter已經在執行的操作。

參數通過匹配 object 上的道具傳遞。

props.match.params.yourParams

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

這是破壞 arguments 中道具的文檔中的示例。

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

您不能從 React.Component 調用諸如“useParams()”之類的鈎子。

如果您想使用鈎子並擁有現有的 react.component,最簡單的方法是創建一個 function 然后從該 function 調用 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>

然后您將能夠從您的反應組件中的道具中獲取 id

this.props.taskId

反應路線 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);

在 react-router-dom-v6 中,您可以輕松地在功能組件中使用 useParams(),但是當它到達 class 組件時,您必須創建 HOC(高階組件),因為鈎子不支持 class 組件:

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")導航到其他組件

SmujMaiku 是正確的。! 他的回答完美。 這就是今天使用 react-router 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-dom v6 中,沒有諸如withRouter 之類的鈎子,因此我對您的建議是將基於類的組件轉換為功能組件以在組件中使用useParams鈎子,否則您可以創建一個高階組件來傳遞你的基於類的組件。

反應路線 v6

我的朋友們,我嘗試在 class 中使用,但我沒有找到任何關於它的文檔。 因此,經過數小時的搜索和努力,這就是(功能)。 現在(即當我寫這篇文章時)關於 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循環。 我用鑰匙阻止了它。

希望:這可能對某人有所幫助!

參考:

在反應路由器 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;

如您所知,useParams() 是 react-router-dom 的掛鈎。 你不能在 componentDidMount() 或 useEffect() 中使用它,因為它們都是在 React 生命周期的掛載階段調用的方法,即在渲染組件之后。 您有一個解決方案:在 componentDidMount() 外部創建或定義另一個 function 以定義 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);

掛鈎僅適用於功能組件,您必須使該組件成為功能組件

通過創建包裝 function 修復

我需要使用 react-router-dom v6 將參數從 index.js 傳遞給我的 SaxjaxApp.js。 在 v6 中, Switch已更改為Routes

通過使用包裝 function 在后 20 中遵循 Mohamed MAZEK 的想法,我得到了 useParams 與 class 組件一起使用。

當它可用時,我需要訪問 url 的sessionId部分。

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

記下這一行: <Route path="/shared/:sessionId" element={<SaxjaxAppWrapper />} />在下面的 index.js 中。

:sessionId表示useParams有一個名為sessionId的屬性,可以通過以下方式訪問:

const {sessionId} = useParams()來自功能組件。

在我的 index.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 />} />調用我的包裝 function,而默認路徑/只調用 class 組件。

我必須創建一個單獨的文件來保存包裝 function 我不知道為什么:

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;

我的 class 組件:

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;

使用 react router 5.1,您可以通過以下方式獲取 id:

<Switch>
  <Route path="/item/:id" component={Portfolio}>
    <TaskDetail />
  </Route>
</Switch>

並且您的組件可以訪問 id:

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

const TaskDetail = () => {
  const {id} = useParams();
    return (
      <div>
        Yo {id}
      </div>
    );
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM