user5512965
user5512965

Reputation: 151

NextJS 13 - Header and Sidebar menu

I am new in NextJS (I am using Next JS 13) and I struggle with the next issue:

In RootLayout I want to add the Header (with a hamburger menu icon), a sidebar menu and the {children} (this is the layout for the entire app)

How can I toggle the display of the sidebar when clicking on the Hamburger icon? Normally I put a state inside the RootLayout and toggle that state from the Header component, and based on it's value show/hide the sidebar component.

But as i read in docs, the RootLayout is a server component and can't have the directive 'use client' (even if it was possible, if I understood correctly, {children} will be also client rendered, so it's not ok)

Upvotes: 3

Views: 3218

Answers (2)

William Chorski
William Chorski

Reputation: 91

like @Mer Mer said, make a separate component for your side bar navigation as a client component.

Then use a Global Context that holds the state of the menu. You'll also gain the ability to trigger the menu's state in any other client component

Client Component

'use client'
import { CartButton } from '@components/ecommerce/CartButton'
import { NavWichButton } from './NavWichButton'
import { SessionBadge } from './Session'

export function Nav() {

  const { isNavOpen, toggleNav } = useNavControl()

  return (
    <nav>

        <button
         onClick={e => toggleNav()}
         id='navwich'
         className={getStyles(isNavOpen)}
        >
         {isNavOpen ? 'Opened' : 'Closed' }
        </button>

        <ul className={styles.menu_main}>
          <li> <a href={`/home`}> Home </a> </li>
          <li> <a href={`/shop`}> Shop </a> </li>
          <li> <a href={`/blog`}> Blog </a> </li>
          <li> <a href={`/users`}> Users </a> </li>
        </ul>

    </nav>
  )
}

Global Context

'use client'
import { createContext, useContext, useState } from "react";

const defaultCtx = {
  isNavOpen: false,
  setisNavOpen: (isSearchOpen: boolean) => { },
  toggleNav: () => { },

}

const GlobalContext = createContext(defaultCtx)

export const GlobalContextProvider = ({ children }: { children: React.ReactNode }) => {

  const [isNavOpen, setisNavOpen] = useState<boolean>(false)


  function toggleNav() { console.log('toggle nav');
   setisNavOpen(!isNavOpen) }


  return (
    <GlobalContext.Provider value={{
      isNavOpen, setisNavOpen, toggleNav,
    }}>
      {children}
    </GlobalContext.Provider>
  )
};



export function useNavControl() {
  const { isNavOpen, setisNavOpen, toggleNav, } = useContext(GlobalContext)
  return { isNavOpen, setisNavOpen, toggleNav, }
}

export const useGlobalContext = () => useContext(GlobalContext);

Don't forget

don't forget to wrap the children in your root layout with this global context

Upvotes: 2

user19297279
user19297279

Reputation:

Create a separate client component that renders the navbar (with the use client directive), then import it in the rootlayout.

Server components can import and render client components.

Upvotes: 0

Related Questions