1

So I'm new to React and JS in general and have been following a course online. The thing is that, after a few chapters, I noticed that some stuff routes-related that the guy does do not work anymore. For example:

<Route path='/something' component={Something}/>

I spent the whole morning searching online. It seems that he uses a different version of react-router-dom than me. So I looked up how to do that same thing in newer versions from their official docs and eventually solved it by implementing routes like:

<Route path='/something' element={<Something/>} />

Now I have another problem. I want to fetch a parameter from the URL but it does not work either and the official docs only offer an example using functions (but I kinda need to use classes).

This is how I currently implement it:

<Route path='/profile/:user' element={<UserInfo/>}/>

UserInfo.js:

import React from 'react';

class UserInfo extends React.Component {
    state = { user: '' }

    componentDidMount() {
        console.log(this)
        let user = this.props.match.params.user;
        this.setState({user:user});
    }

    render() {
        const { user } = this.state
        return(
            <div>
                <h1>{user}</h1>
            </div>
        )
    }
}

export default Card

But it does not work either because this.props is empty "props: Object { }". There should be a match object but there is nothing inside (according to the dev console). How can I solve this without making UserInfo a function? Because I want to have states.

Ricardo
  • 337
  • 5
  • 16
  • See marked duplicate, it's exactly your situation for needing to access the route match params from a class component. The answers here didn't seem to address your actual issue. – Drew Reese Feb 02 '22 at 15:58

3 Answers3

1

With react-router-dom V6 you can e.g. create a very simple HOC(higher order component) to be able to use useParams inside a class component.

HOC.js

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


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

Then include it in UserInfo.js

import React from "react";
import { withParams } from "./HOC";

class UserInfo extends React.Component {
  constructor(props) {
    super(props);
    this.state = { user: "" };
  }

  componentDidMount() {
    let user = this.props.params.user;
    console.log(user);
    this.setState({ user: user });
  }

  render() {
    return (
      <div>
        <h1>{this.state.user}</h1>
      </div>
    );
  }
}

export default withParams(UserInfo);

index.js

import ReactDOM from "react-dom";
import { BrowserRouter, Route, Routes } from "react-router-dom";

import UserInfo from "./UserInfo";

const rootElement = document.getElementById("root");
ReactDOM.render(
  <BrowserRouter>
    <Routes>
      <Route path={"/profile/:user"} element={<UserInfo />} />
    </Routes>
  </BrowserRouter>,
  rootElement
);

Here is a Sandbox in case you need it:

The old react-router-dom V5 solution would be:

import { StrictMode } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route } from "react-router-dom";

import UserInfo from "./UserInfo";

const rootElement = document.getElementById("root");
ReactDOM.render(
  <StrictMode>
    <BrowserRouter>
      <Route path={["/profile/:user"]} component={UserInfo} />
    </BrowserRouter>
  </StrictMode>,
  rootElement
);

And access the user data inside the class component like that:

import React from "react";

class UserInfo extends React.Component {
  constructor(props) {
    super(props);
    this.state = { user: "" };
  }

  componentDidMount() {
    let user = this.props.match.params.user;
    console.log(user);
    this.setState({ user: user });
  }

  render() {
    const { user } = this.state;
    return (
      <div>
        <h1>{user}</h1>
      </div>
    );
  }
}

export default UserInfo;
MWO
  • 2,627
  • 2
  • 10
  • 25
1

There is no reason to have a class here, they kinda useless now that we have hooks. To get a state in a functional component, you can use the hook useState. This way you reproduce what you know about state in a class, but in a function. Here is an example :

import React, { Component } from "react";
import { render } from "react-dom";
import "./style.css";

const App = () => {
  const [myState, setMyState] = React.useState();

  return (
    <div>
       My state = {myState}<br />
       <button onClick={() => setMyState(Math.random())}> Edit my state</button>
    </div>
  );
};

render(<App />, document.getElementById("root"));
Quentin Grisel
  • 4,794
  • 1
  • 10
  • 15
  • Thanks. I will keep that in mind for future projects. Anyway, just for the sake of following the current course, do you know how to fix the class implementation? – Ricardo Feb 02 '22 at 13:52
  • 1
    @Ricardo You're welcome. For your problem, either downgrade your react-router-dom version to the v5 or below (Really not recommanded) or find another tutorial that is up to date. The one you are following isn't really good to strat learning React nowadays. This technology had a major change in its way of coding with the Hooks and functional compoent. They really shouldn't be ignored since you'll see it everywhere (And it's easier). – Quentin Grisel Feb 02 '22 at 14:03
0

Try to add:


constructor(props) {
  this.state = { user: '' };
}

instead of :


state = { user: '' }

I didn't run your code but I saw that immediately. And consider using functional components with hooks instead, that newer way and it standardizes react code.