Search code examples
reactjsreact-routerreact-router-dom

Can't get React Router to work in my React app


I'm trying to get a button to route to a specific component and it just does nothing but change the address in the navbar.

Here's my index.js file:

    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import {
      createBrowserRouter,
      createRoutesFromElements,
      Route,
      RouterProvider
    } from 'react-router-dom';
    import './index.css';
    import App from './App';
    import Email from './screens/Email';
    import reportWebVitals from './reportWebVitals';
    const router = createBrowserRouter(
      createRoutesFromElements(
        <Route path="/" element={<App />}>
          <Route path="email" element={<Email />} />
        </Route>
      )
    )
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(
      <React.StrictMode>
        <RouterProvider router={router}></RouterProvider>
      </React.StrictMode>
    );
    reportWebVitals();

////////////////////////// And here's my App.js file:

    import React, { useState, useEffect } from 'react';
    import './App.css';
    import Language from './screens/Language';
    import PreLoader from './components/PreLoader';

    function App() {

      const [isLoading, setIsLoading] = useState(true);

      useEffect(() => {
        setTimeout(() => {
          setIsLoading(false);
        }, 3000);
      }, []);

      return (
        <div>
          {isLoading ? <PreLoader /> : <Language />}
        </div>
      );
    }

    export default App;

The button is in the Language component like this: <div className="btn-container"><Link to='email'><button className="button">Continue</button> </Link></div>

I'm sure it's something obvious but I just can't find it. Thanks in advance!

Clicking the button should render the Email component but it doesn't. The web address changes to localhost:3000/email but the page remains the same (the Language component).

EDIT: I haven't included all code for the sake of brevity. renders a splash screen and then the component, which contains the button. So it should go:

  • Splash screen
  • Language screen (language selection)
  • Email screen (for email address input) Perhaps should add that this is an interview take-home test, and I'm out of my depth.

Solution

  • Issues

    1. The App component is missing rendering an Outlet component for the nested "/email" route to render its element content into.
    2. The Language component is using a relative link target path instead of an absolute path. If the user is already on "/email" and the link/button is clicked again, the app will navigate relative to the current path and result in the URL path being "/email/email", and so on. Absolute paths start with a leading "/" character, relative paths do not.

    Solution

    Add an Outlet to App for the nest route:

    import React, { useState, useEffect } from 'react';
    import { Outlet } from 'react-router-dom';
    import './App.css';
    import Language from './screens/Language';
    import PreLoader from './components/PreLoader';
    
    function App() {
      const [isLoading, setIsLoading] = useState(true);
    
      useEffect(() => {
        setTimeout(() => {
          setIsLoading(false);
        }, 3000);
      }, []);
    
      return (
        <div>
          {isLoading ? <PreLoader /> : <Language />}
          <Outlet />
        </div>
      );
    }
    
    export default App;
    

    If you didn't intend for Language to be rendered at the same time as the Email component then you'll want to unnest the email route. This is to make each route/page independently matched and rendered.

    const router = createBrowserRouter(
      createRoutesFromElements(
        <>
          <Route path="/" element={<App />} />
          <Route path="email" element={<Email />} />
        </>
      )
    );
    
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(
      <React.StrictMode>
        <RouterProvider router={router} />
      </React.StrictMode>
    );
    

    Use an absolute link target path to the email page:

    <div className="btn-container">
      <Link to="/email">
        <button className="button">Continue</button>
      </Link>
    </div>