Search code examples
reactjstypescriptreact-router-domnavbar

React HashRouter, I have a problem with the page reloading when clicking on the nav bar


When I try to change the page and click on the nav bar it changes to url but until I manually click on reload page it won't change.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import HomePage from './components/HomePage/HomePage';
import reportWebVitals from './reportWebVitals';
import 'bootstrap/dist/css/bootstrap.min.css';
import 'jquery/dist/jquery.js';
import 'popper.js/dist/popper.js';
import 'bootstrap/dist/js/bootstrap.min.js';
import '@fortawesome/fontawesome-free/css/fontawesome.min.css'
import { MainMenu, MainMenuItem } from './components/MainMenu/MainMenu';
import { HashRouter, Routes, Route } from 'react-router-dom';
import { ContactPage } from './components/ContactPage/ContactPage';
import { UserLoginPage } from './components/UserLoginPage/UserLoginPage';

const menuItems = [
  new MainMenuItem("Home", "/"),
  new MainMenuItem("Contact", "/contact"),
  new MainMenuItem("Log in", "/user/login"),
];

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

root.render(
  <React.StrictMode>
    <MainMenu items={menuItems} />
    <HashRouter>
      <Routes>
        <Route index path='/' element={<HomePage />} />
        <Route path="/contact" element={<ContactPage />} />
        <Route path="/user/login" element={<UserLoginPage />} />
     </Routes>
    </HashRouter>
  </React.StrictMode>
);

reportWebVitals();

This is another class that needs to align my nav bar.

import React from 'react';
import { Nav, Container } from 'react-bootstrap';
import { HashRouter , Link } from 'react-router-dom';

export class MainMenuItem {
  text: string = '';
  link: string = '#';

  constructor(text: string, link: string) {
    this.text = text;
    this.link = link;
  }
}

interface MainMenuProperties {
  items: MainMenuItem[];
}

interface MainMenuState {
  items: MainMenuItem[];
}

export class MainMenu extends React.Component<MainMenuProperties>{
  state: MainMenuState;

  constructor(props: Readonly<MainMenuProperties>) {  
    super(props);
    this.state = {
      items: props.items,
    };
  }

  public setItems(items: MainMenuItem[]) {
    this.setState({
      items: items,
    });
  }

  render() {
    return (
      <Container>
        {this.state.items.map(this.makeNewLink)}
    );
  }

  private makeNewLink(item: MainMenuItem, index: number) {
    return (
      <Link key={index} to={item.link} className='nav-link'>
        {item.text}
      </Link>
    );
  }
}


Solution

  • You are rendering the application links (Link) in MainMenu which is rendering it's own router while the routes you want to navigate to are rendered in their own HashRouter in the index.js.

    You need only one router per app, and all React-Router components (Link, Route, etc) and hooks (useLocation, etc).

    1. Remove HashRouter from MainMenu.
    2. Move MainMenu into the main HashRouter.
    import React from 'react';
    import { Nav, Container } from 'react-bootstrap';
    import { Link } from 'react-router-dom';
    
    ...
    
    export class MainMenu extends React.Component<MainMenuProperties>{
      state: MainMenuState;
    
      constructor(props: Readonly<MainMenuProperties>) {  
        super(props);
        this.state = {
          items: props.items,
        };
      }
    
      public setItems(items: MainMenuItem[]) {
        this.setState({
          items,
        });
      }
    
      render() {
        return (
          <Container>
            {this.state.items.map(this.makeNewLink)}
          </Container>
        );
      }
    
      private makeNewLink(item: MainMenuItem, index: number) {
        return (
          <Link key={index} to={item.link} className='nav-link'>
            {item.text}
          </Link>
        );
      }
    }
    
    const menuItems = [
      new MainMenuItem("Home", "/"),
      new MainMenuItem("Contact", "/contact"),
      new MainMenuItem("Log in", "/user/login"),
    ];
    
    const root = ReactDOM.createRoot(
      document.getElementById('root') as HTMLElement
    );
    
    root.render(
      <React.StrictMode>
        <HashRouter>
          <MainMenu items={menuItems} />
          <Routes>
            <Route index path='/' element={<HomePage />} />
            <Route path="/contact" element={<ContactPage />} />
            <Route path="/user/login" element={<UserLoginPage />} />
          </Routes>
        </HashRouter>
      </React.StrictMode>
    );