Navigate from parent to child in react where each component defines its own routes

Viewed 1850

In a React app with a parent and child elements, I want to achieve the following when navigating to /Parent/Child:

  1. I want Child to be rendered on a new page.
  2. I want to avoid defining a route for /Parent/Child in index.js (the topmost file).

Currently, in the following code (see it live), when navigating to /Parent/Child, both parent and child are rendered, thus breaking requirement #1. The reason is that <Route path='/Parent' component={Parent} /> doesn't have the exact attribute.

However, making it <Route exact path='/Parent' component={Parent} /> won't work as well, since Child won't be rendered at all (see it live), which I understand why.

An optional solution is to add /Parent/Child route in index.js (and also get rid of the Route in Parent, see it live), but it breaks requirement #2.

So, is it possible to achieve both requirements? if so, how?

  • React version is 17, react-router-dom version is 5.

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import Parent from './Parent';
import { BrowserRouter as Router, Switch, Route, Redirect } from 'react-router-dom'

ReactDOM.render(
  <React.StrictMode>
    <Router>
      <Switch>
        <Route path='/Parent' component={Parent} />
      </Switch>
      <Redirect from='/' to="/Parent" />
    </Router>
  </React.StrictMode >,
  document.getElementById('root')
);

Parent.js

import Child from './Child';
import { Route, useRouteMatch, useHistory } from 'react-router-dom'

function Parent() {
  const history = useHistory();
  const match = useRouteMatch();
  return (
    <div>
      <Route path={`${match.path}/Child`} component={Child} />
      <h1>Parent</h1>
      <a target="_blank" onClick={() => history.push(`${match.path}/Child`)}>Navigate To Child</a>
    </div>
  );
}

export default Parent;

Child.js

import BackButton from './BackButton';

function Child() {
  return (
    <div>
      <h1>Child</h1>
      <BackButton>Go Back</BackButton>
    </div>
  );
}

export default Child;

BackButton.js

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

function BackButton({ children }) {
  let history = useHistory()
  return (
    <button type="button" onClick={() => history.goBack()}>
      {children}
    </button>
  )
}
export default BackButton;
1 Answers

You can treat the Parent as an "index" page. Using another Switch you can render "child of" routes and a default fallback route. This takes advantage of the Switch component's matching and rendering only a single Route or Redirect component.

function Parent() {
  const history = useHistory();
  const match = useRouteMatch();
  return (
    <div>
      <Switch>
        <Route path={`${match.path}/Child`} component={Child} />
        <Route>
          <h1>Parent</h1>
          <a
            target="_blank"
            onClick={() => history.push(`${match.path}/Child`)}
          >
            Navigate To Child
          </a>
        </Route>
      </Switch>
    </div>
  );
}

Edit navigate-from-parent-to-child-in-react-where-each-component-defines-its-own-rout

Related