skip to Main Content

I have a sidebar menu that has been successfully hidden and shown. When the sidebar menu is hidden and I refresh the page or browser, the hidden sidebar menu will return to its original appearance
How can I avoid this? I want the sidebar open instead on desktop view. It is a dashboard.

This is the ContextProvider.js

import { useState, createContext, useContext, useEffect } from "react";

const StateContext = createContext()
const initialState = {
    cart: false,
    notification: false,
    searchBar: false,
}

export const ContextProvider = ({ children }) => {
    const [activeMenu, setActiveMenu] = useState(true)
    const [isClicked, setIsClicked] = useState(initialState)
    const [screenSize, setScreenSize] = useState(undefined)
    const [currentColor, setCurrentColor] = useState('#bf9a8e')
    const [currentMode, setCurrentMode] = useState('Light')
    const [isOpen, setIsOpen] = useState(false)
    const [currentIndex, setCurrentIndex] = useState(0)

    

    const setMode = (e) => {
        setCurrentMode(e.target.value);
        localStorage.setItem('themeMode', e.target.value);
      };

      const setColor = (color) => {
        setCurrentColor(color);
        localStorage.setItem('colorMode', color);
      };

    const handleClick = (clicked) => {
        setIsClicked({...initialState, [clicked]: true})
    }

    const slideLeft = () => {
        let slider = document.getElementById('slider-2')
        slider.scrollLeft = slider.scrollLeft - 500
      }

    const slideRight = () => {
        let slider = document.getElementById('slider-2')
        slider.scrollLeft = slider.scrollLeft + 500
      }


    return (
        <StateContext.Provider value={{ 
            activeMenu,
            setActiveMenu,
            isClicked,
            setIsClicked,
            handleClick,
            screenSize,
            setScreenSize, currentColor,
            currentMode,
            setColor,
            setMode,
            isOpen, 
            setIsOpen, 
            slideLeft,
            slideRight,
            currentIndex, 
            setCurrentIndex, 
         }}>
            {children}
        </StateContext.Provider>
    )
}

export const useStateContext = () => useContext(StateContext)

I think I should place a useEffect hook to change the initial state but I am not sure if it can solve this issue. This is my sidebar component

function Sidebar() {

  const { activeMenu, setActiveMenu, screenSize, currentColor } = useStateContext();

  const handleCloseSideBar = () => {
    if (activeMenu !== undefined && screenSize <= 900) {
      setActiveMenu(false);
    }
  };

  const activeLink = 'flex items-center gap-5 pl-4 pt-3 pb-2.5 text-gray-100 dark:text-white rounded-lg bg-slate-700 text-md m-2'
  const normalLink = 'flex items-center gap-5 pl-4 pt-3 pb-2.5 rounded-lg text-md dark:text-gray-300 text-gray-500 dark:hover:text-gray-600 m-2 hover:bg-gray-200';

  return (
    <div className="mr-4 ml-4 mt-3 scrollbar-hide h-screen md:overflow-hidden overflow-auto md:hover:overflow-auto pb-10">
      {/* LOGO SECTION */}
      {activeMenu && (
        <>
          <div className="flex text-slate-700 dark:text-white justify-between">
            <Link
              to="/"
              onClick={handleCloseSideBar}
              className="flex text-xl font-extrabold items-center gap-3 ml-4 mt-4 tracking-tight"
            >
              <GiPlanetCore/>
              <span>BaIlEyWoRld</span>
            </Link>
            <button
              type="button"
              onClick={() => setActiveMenu((prevActiveMenu) => !prevActiveMenu)}
              className="text-2xl p-3 mt-4 block sm:hidden"
            >
              <MdClose />
            </button>
          </div>
          <div className="mt-10">
            {links.map((item) => (
              <div key={item.title}>
                <p className="text-gray-400 dark:text-gray-200 font-semibold uppercase m-4 mt-4">
                  {item.title}
                </p>
                {item.links.map((link) => (
                  <NavLink
                    to={`/${link.name}`}
                    key={link.name}
                    onClick={handleCloseSideBar}
                    className={({isActive}) =>
                      isActive ? activeLink : normalLink
                    }
                    style={({isActive}) => ({backgroundColor: isActive ? currentColor : ''})}
                  >
                    {link.icon}
                    <span>{link.name}</span>
                  </NavLink>
                ))}
              </div>
            ))}
          </div>
        </>
      )}
    </div>
  );
}

export default Sidebar

3

Answers


  1. This is because you can’t keep a state when you refresh your page. A solution could be to use query params and add for example ?open=true when your activeMenu change. So in that case you can get the previous state when the page is refreshed and set it true by default.

    ex:

    import { useState, createContext, useContext, useEffect } from "react";
    import { useLocation, useSearchParams } from "react-router-dom";
    import queryString from "query-string";
    
    const StateContext = createContext()
    const initialState = {
        cart: false,
        notification: false,
        searchBar: false,
    }
    
    export const ContextProvider = ({ children }) => {
        let location = useLocation();
        const [, setSearchParams] = useSearchParams();
        const [activeMenu, setActiveMenu] = useState(true)
        const [isClicked, setIsClicked] = useState(initialState)
        const [screenSize, setScreenSize] = useState(undefined)
        const [currentColor, setCurrentColor] = useState('#bf9a8e')
        const [currentMode, setCurrentMode] = useState('Light')
        const [isOpen, setIsOpen] = useState(false)
        const [currentIndex, setCurrentIndex] = useState(0)
    
         useEffect(() => {
            const parsed = queryString.parse(location.search)
    
            if (parsed.open === 'true') setActiveMenu(true)
         }, [])
    
         const onActiveMenuChange = (value) => {
            setActiveMenu(value)
    
            setSearchParams({
              open: value ? true : false,
            })
         }
    
        const setMode = (e) => {
            setCurrentMode(e.target.value);
            localStorage.setItem('themeMode', e.target.value);
          };
    
          const setColor = (color) => {
            setCurrentColor(color);
            localStorage.setItem('colorMode', color);
          };
    
        const handleClick = (clicked) => {
            setIsClicked({...initialState, [clicked]: true})
        }
    
        const slideLeft = () => {
            let slider = document.getElementById('slider-2')
            slider.scrollLeft = slider.scrollLeft - 500
          }
    
        const slideRight = () => {
            let slider = document.getElementById('slider-2')
            slider.scrollLeft = slider.scrollLeft + 500
          }
    
    
        return (
          <StateContext.Provider
            value={{
              activeMenu,
              setActiveMenu: onActiveMenuChange,
              isClicked,
              setIsClicked,
              handleClick,
              screenSize,
              setScreenSize,
              currentColor,
              currentMode,
              setColor,
              setMode,
              isOpen,
              setIsOpen,
              slideLeft,
              slideRight,
              currentIndex,
              setCurrentIndex,
            }}
          >
            {children}
          </StateContext.Provider>
        );
    }
    
    export const useStateContext = () => useContext(StateContext)
    
    
    Login or Signup to reply.
  2. To maintain the state of the sidebar menu being hidden or shown even after a page refresh, you can utilize local storage to store the state information and retrieve it when the page reloads.
    Add this in your Sidebar

    import { useEffect } from "react";
    import { useStateContext } from "./ContextProvider";
    
    
    function Sidebar(){
     const { activeMenu, setActiveMenu, screenSize, currentColor, isOpen, setIsOpen } = useStateContext(); 
      
     // handle closing sidebar based on conditions
     const handleCloseSideBar = () => {
       if (activeMenu !== undefined && screenSize <= 900) {
        setActiveMenu(false);
        setIsOpen(false);
       }
     };
      
     // handle opening sidebar based on conditions
     const handleOpenSideBar = () => {
      if (activeMenu !== undefined && screenSize <= 900) {
       setActiveMenu(true);
       setIsOpen(true);
      }
     };
    
     useEffect(() => {
      const storedIsOpen = localStorage.getItem("sidebarOpen");
      if (storedIsOpen !== null) {
       setIsOpen(storedIsOpen === "true");
      }
     }, [setIsOpen]);
     
     // and here add other parts of your component remain unchanged
    
    }
    
    Login or Signup to reply.
  3. You can update the useEffect hook in your ContextProvider.js file to store the state in localStorage whenever it changes and retrieve it when the component mounts.

    export const ContextProvider = ({ children }) => {
      // ... (other state variables and functions)
    
     
      useEffect(() => {
        const storedIsOpen = localStorage.getItem('isOpen');
    
        if (storedIsOpen !== null) {
          setIsOpen(JSON.parse(storedIsOpen));
        } else {
          setIsOpen(false);
        }
      }, []);
    
      useEffect(() => {
        localStorage.setItem('isOpen', JSON.stringify(isOpen));
      }, [isOpen]);
    

    "whenever the isOpen state changes, it will be stored in localStorage. And when the component mounts, it will check if there is a stored value and set the state accordingly"

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search