Search code examples
javascriptreactjsreact-hooksreact-routerreact-router-dom

The divs remain invisible after clicking the browser back button


I have used react-router in App.jsx where the parent component is the Main component with following Routes

<Route path="/" element={<Main />}>
  <Route path="login" element={<Login />} />
  <Route path="signup" element={<SignUp />} />
</Route>

In Main.jsx I have used NavLink on two "Button" components for Login and Signup to the above respective routes. The Buttons have handleClick function which applies a class called "invisible" to the two divs mentioned below which sets the display property to none using conditional rendering to hide the divs and only render the <Outlet /> (Login or the SignUp component). But when you try to go to back to the "/" route using the browser back button the divs are still invisible and the page need to be reloaded in order for it to be visible.

App.jsx

import React, { useState } from "react";
import Main from "./Main";
import SignUp from "./SignUp";
import Login from "./Login";
import Home from "./Home";
import {  createBrowserRouter, createRoutesFromElements, Route, RouterProvider,} from "react-router-dom";

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path="/" element={<Main />}>
      <Route path="login" element={<Login />} />
      <Route path="signup" element={<SignUp />} />
    </Route>
  )
);

function App() {
  return <RouterProvider router={router} />;
}

export default App;

Main.jsx

import React, { useState } from "react";
import Button from "./Button";
import { NavLink, Outlet } from "react-router-dom";

function Main() {
  const [isVisible, setIsVisible] = useState(true);

  const handleClick = () => {
    setIsVisible(false);
  };

  return (
    <div className="main-div">
      <div className={`main-heading-div ${isVisible ? "" : "invisible"}`}>
        <p className="main-heading">
          Welcome to <span>The Book Keeper</span>
        </p>
        <p>Your Personal Library, Perfectly Organized</p>
      </div>

      <div className={`button-div ${isVisible ? "" : "invisible"}`}>
        <NavLink to="/login">
          <Button text="Log in" name="main-login" onClick={handleClick} />
        </NavLink>
        <NavLink to="/signup">
          <Button text="Sign Up" name="main-signup" onClick={handleClick} />
        </NavLink>
      </div>

      <Outlet />
    </div>
  );
}

export default Main;

This problem arose when I tried to solve a previous problem of, the result of the <Outlet /> overlapping with with contents of the Main component when any of the NavLink where clicked. So I tried to solve this by used useState + css and then arrived at this issue.


Solution

  • To reset the isVisible state back to true when the user navigates to the "/" root route you could use the useMatch and useEffect hooks to check for that match explicitly and reset the state.

    Example:

    import { NavLink, Outlet, useMatch } from 'react-router-dom';
    
    function Main() {
      const [isVisible, setIsVisible] = useState(true);
    
      const homeMatch = useMatch("/");
    
      useEffect(() => {
        if (homeMatch) {
          setIsVisible(true);
        }
      }, [homeMatch, setIsVisible]);
    
      const handleClick = () => {
        setIsVisible(false);
      };
    
      ...
    }
    

    Of course, if all you are really trying to accomplish is for the Main component content to only be rendered on "/" then it might be more advisable to refactor that into an index route component.

    Example:

    const MainPage = () => (
      <>
        <div className="main-heading-div">
          <p className="main-heading">
            Welcome to <span>The Book Keeper</span>
          </p>
          <p>Your Personal Library, Perfectly Organized</p>
        </div>
    
        <div className="button-div">
          <NavLink to="/login">
            <Button text="Log in" name="main-login" />
          </NavLink>
          <NavLink to="/signup">
            <Button text="Sign Up" name="main-signup" />
          </NavLink>
        </div>
      </>
    );
    
    function Main() {
      return (
        <div className="main-div">
          <Outlet />
        </div>
      );
    }
    
    const router = createBrowserRouter(
      createRoutesFromElements(
        <Route path="/" element={<Main />}>
          <Route index element={<MainPage />} />
          <Route path="login" element={<Login />} />
          <Route path="signup" element={<SignUp />} />
        </Route>
      )
    );