Linking to a component from the same component doesn't work

Viewed 67

I have a component, let's say MyComponent, accessible through a route like this:

 <Route path="/myComponent/:id" exact component={MyComponent} />

Inside MyComponent I have:

 <Link to="/myComponent/2">2</Link>

That is, MyComponent links to itself. But this link does not work! If I inspect the React component through Chrome's developer tools, then props.match has been updated accordingly, but MyComponent has not been re-rendered and the constructor has not been recalled so that the state can be updated accordingly.

Minimal example: https://codesandbox.io/s/sharp-bouman-i1b0p?fontsize=14 - if you browse to this URL then you'll see the ID 1 appear on the rendered screen, but if you click on the 2 link the screen will not rerender even though the URL does update. If you go to this URL then the ID 2 will appear as expected.

2 Answers

If the component is already mounted, React router reuses the component instance. Hence constructor or componentDidMount hooks are not called.

You can fix this by adding a componentDidUpdate:

componentDidUpdate(prevProps) {
  const { id } = this.props.match.params;
  if(id !== this.state.id) {
    this.setState({
      id
    });
  }
}

Codesandbox

AAAH ! It does re-render with no problem. It is just your state.id that is never updated. You should either use your props as-is or keep your state up-to-date:

import React, { Component } from "react";
import { Link } from "react-router-dom";

export default class MyComponent extends Component {
  constructor(props) {
    super(props);

    const {
      match: { params }
    } = this.props;

    this.state = {
      // This will only ever happen once !
      id: params.id
    };
  }
  // this will keep your state in sync with your props
  componentDidUpdate (lastProps) {
    if (lastProps.match.params.id !== this.props.match.params.id) {
      this.setState({ id: this.props.match.params.id }) 
    }
  }
  render() {
    // uncommenting the following line and deleting the next one will make your whole state useless
    // const { id } = this.props.match.params
    const { id } = this.state

    return (
      <div>
        <div>{id}</div>
        <Link to="/myComponent/2">2</Link>
      </div>
    );
  }
}
Related