Search code examples
reactjsreact-router-domreact-router-v4

React-Router: Component is not rendered but URL changes


I am new to React js. I am implementing the drawer (material-ui), so when user clicks on left menu (LeftMenu.jsx); the respective component should get render in the center (i.e, MainContent.jsx)

Unfortunately, I am getting following error: Error: Invariant failed: You should not use <Link> outside a <Router> But if I enclosed Link in LeftMenu.jsx then URL changes but view does not get render.

I tried the solutions given in React router changes url but not view but still the problem is not solved.

Following are the list of components:

Status.jsx

import React, { Component } from "react";
class Status extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }
  render() {
    return <div>Status</div>;
  }
}
export default Status;

AdminPanelLayout.jsx

export default function AdminPanelLayout() {
  const classes = useStyles();
  const theme = useTheme();
  const [open, setOpen] = React.useState(false);

  const handleDrawerOpen = () => {
    if (open) {
      setOpen(false);
    } else {
      setOpen(true);
    }
  };

  const handleDrawerClose = () => {
    setOpen(false);
  };

  return (
    <div className={classes.root}>
      <CssBaseline />
      <AppBar
        position="fixed"
        className={clsx(classes.appBar, {
          [classes.appBarShift]: open,
        })}
      >
        <Toolbar>
          <IconButton
            color="inherit"
            aria-label="open drawer"
            onClick={handleDrawerOpen}
            edge="start"
          >
            <MenuIcon />
          </IconButton>
          <Typography variant="h6" noWrap>
            Admin Panel
          </Typography>
        </Toolbar>
      </AppBar>
      <Drawer
        variant="permanent"
        className={clsx(classes.drawer, {
          [classes.drawerOpen]: open,
          [classes.drawerClose]: !open,
        })}
        classes={{
          paper: clsx({
            [classes.drawerOpen]: open,
            [classes.drawerClose]: !open,
          }),
        }}
      >
        <div className={classes.toolbar}></div>
        <Divider />
        <LeftMenu></LeftMenu>
      </Drawer>
      <MainContent></MainContent>
    </div>
  );
}

MainContent.jsx

export default function MainContent() {
  const classes = useStyles();
  return (
    <Router>
      <main className={classes.content}>
        <div className={classes.toolbar} />
        <Switch>
          <Route path="/Status" component={withRouter(Status)}>
            <Status />
          </Route>
          <Route path="/">
            <span>testing</span>
          </Route>
        </Switch>
      </main>
    </Router>
  );
}

LeftMenu.jsx

export default function LeftMenu() {
  return (
    <div>
      <List>
        {["Status", "Starred", "Send email", "Drafts"].map((text, index) => (
          <ListItem button key={text} component={Link} to="/Status">
            <ListItemIcon>
              {index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
            </ListItemIcon>
            <ListItemText primary={text} />
          </ListItem>
        ))}
      </List>
      <Divider />
      <List>
        {["All mail", "Trash", "Spam"].map((text, index) => (
          <ListItem button key={text}>
            <ListItemIcon>
              {index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
            </ListItemIcon>
            <ListItemText primary={text} />
          </ListItem>
        ))}
      </List>
    </div>
  );
}

App.js

import "./App.css";
import AdminPanelLayout from "./components/AdminPanelLayout";
import LeftMenu from "./components/LeftMenu";

function App() {
  return <AdminPanelLayout></AdminPanelLayout>;
}

export default App;


Solution

  • You should either use

    <Route path="/Status" component={Status}>
    

    or

    <Route path="/Status">
     <Status />
    </Route>
    

    Also you should not be doing this component={withRouter(Status)} because this is equivalent to component={Status}. The purpose of withRouter is to get a component which is not rendered via Route to get access to the route props . Since Status is already rendered via Route wrapping it with withRouter is not needed.

    codesanbox - Hope this helps !