Search code examples
reactjsreact-router-domreact-bootstrap

React router dom 6 and bootstrap 2.5 nav link renders entire app


When I click on a Nav.link in my SPA application the entire page re-renderss, but I only want the content in the main portion of the UI to change based on the link being clicked. In the layout I have a header nav and then one row and two columns. The content of the header nav never changes, and the left column is a static list of clickable Nav links. The only content I want to change is the content of the right column based on the link that is clicked, and I do not want to re-render the entire app, just the content of the column.

App.js

const rootElement = document.getElementById('root');
const root = createRoot(rootElement);

root.render(
  <React.StrictMode>
    <BrowserRouter>
      <CommonComponent/>
    </BrowserRouter>
  </React.StrictMode>
);

CommonComponent

    <>
      <Navbar>
        <div></div>
      </Navbar>
      <Container fluid>
        <Row>
          <Col xs={4} sm={4} md={4} lg={3} xl={2}>
            <Nav.Item href="/a">
              <Nav.Link href="a">Comp A</Nav.Link>
            </Nav.Item>
            <Nav.Item>
              <Nav.Link href="b">Comp B</Nav.Link>
            </Nav.Item>
            <Nav.Item>
              <Nav.Link href="c">Comp C</Nav.Link>
            </Nav.Item>
            <Nav.Item>
              <Nav.Link href="d">Comp D</Nav.Link>
            </Nav.Item>
          </Col>
          <Col xs={8} sm={8} md={8} lg={9} xl={10}>
            <Routes>
              <Route path="/" element={<Navigate to="a" replace />} />
              <Route path="/a" element={<CompA {...props} />} />
              <Route path="/b" element={<CompB {...props} />} />
              <Route path="/c" element={<Compc {...props} />} />
              <Route path="/d" element={<CompD {...props} />} />
            </Routes>
          </Col>
        </Row>
      </Container>
    </>

The CompA, CompB, etc, are just different forms, nothing complicated. However any click on the side nav links renders the entire app.


Solution

  • I believe the issue is that the Nav.Link component renders a raw anchor tag by default. You want to render a react-router-dom Link component though.

    Try importing the Link from react-router-dom and rendering that as the Nav.Link component.

    See Nav.Link props.

    Pass the Link to the Nav.Link component's as prop and change href to to for the Link component's target. You'll probably also want to use absolute paths.

    Example:

    import { Link, Routes, Route } from 'react-router-dom';
    
    ...
    
    <>
      <Navbar>
        <div></div>
      </Navbar>
      <Container fluid>
        <Row>
          <Col xs={4} sm={4} md={4} lg={3} xl={2}>
            <Nav.Item href="/a">
              <Nav.Link as={Link} to="/a">Comp A</Nav.Link>
            </Nav.Item>
            <Nav.Item>
              <Nav.Link as={Link} to="/b">Comp B</Nav.Link>
            </Nav.Item>
            <Nav.Item>
              <Nav.Link as={Link} to="/c">Comp C</Nav.Link>
            </Nav.Item>
            <Nav.Item>
              <Nav.Link as={Link} to="/d">Comp D</Nav.Link>
            </Nav.Item>
          </Col>
          <Col xs={8} sm={8} md={8} lg={9} xl={10}>
            <Routes>
              <Route path="/" element={<Navigate to="/a" replace />} />
              <Route path="/a" element={<CompA {...props} />} />
              <Route path="/b" element={<CompB {...props} />} />
              <Route path="/c" element={<Compc {...props} />} />
              <Route path="/d" element={<CompD {...props} />} />
            </Routes>
          </Col>
        </Row>
      </Container>
    </>