Search code examples
javascriptreactjsreact-routerreact-router-dom

Error using useNavigate() in when navigating with React Router


I have the file App.js:

import './App.css';
import Login from './Login';

function App() {
  return (
    <div className="App">
      <Login />
    </div>
  );
}

export default App;

And the Index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Login from "./Login";
import Table from "./Table.tsx"; 
import HomePage from "./HomePage"; 

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
        <Route index element={<App />} />
        <Route path="login" element={<Login />} />
        <Route path="homepage" element={<HomePage />} />
        <Route path="table" element={<Table />} />
      </Routes>
    </BrowserRouter>
  </React.StrictMode>
);

Now, I want to add an icon to go back to homepage from table page, but it gives me the following error:

ERROR: useNavigate() may be used only in the context of a component.

To complete this is the Table.tsx file:

import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom/client';
import './Table.css';

const Table = () => {
 const navigate = useNavigate();

 const handleGoHome = () => {
   navigate("/homepage");
 };     

 return (
   <div className="home-button-container">
    <Button variant="primary" onClick={handleGoHome}>Home</Button>
  </div>
 );
};

const rootElement = document.getElementById('root');
if (!rootElement) throw new Error('Failed to find the root element');

ReactDOM.createRoot(rootElement).render(
  <React.StrictMode>
    <Table />
  </React.StrictMode>
);

export default Table;

Solution

  • Issue

    The code is rendering an additional Table component also into the "root" element for some reason, and this additional Table component is rendered alone without any routing context to provide anything for the useNavigate hook.

    const Table = () => {
     const navigate = useNavigate();
    
     const handleGoHome = () => {
       navigate("/homepage");
     };     
    
     return (
       <div className="home-button-container">
        <Button variant="primary" onClick={handleGoHome}>Home</Button>
      </div>
     );
    };
    
    const rootElement = document.getElementById('root');
    if (!rootElement) throw new Error('Failed to find the root element');
    
    ReactDOM.createRoot(rootElement).render(
      <React.StrictMode>
        <Table /> // <-- No router!!!
      </React.StrictMode>
    );
    
    export default Table;
    

    Solution

    Since Table is already rendered correctly in a route in the index.js file:

    const root = ReactDOM.createRoot(document.getElementById("root"));
    root.render(
      <React.StrictMode>
        <BrowserRouter>
          <Routes>
            <Route index element={<App />} />
            <Route path="login" element={<Login />} />
            <Route path="homepage" element={<HomePage />} />
            <Route path="table" element={<Table />} />
          </Routes>
        </BrowserRouter>
      </React.StrictMode>
    );
    

    I see no reason for the extraneous render to the DOM. Remove the extra code from Table.jsx

    import React, { useState, useEffect } from 'react';
    import './Table.css';
    
    const Table = () => {
     const navigate = useNavigate();
    
     const handleGoHome = () => {
       navigate("/homepage");
     };     
    
     return (
       <div className="home-button-container">
        <Button variant="primary" onClick={handleGoHome}>Home</Button>
      </div>
     );
    };
    
    export default Table;