NextJS app router - where to put overall state?

28 Views Asked by At

I am quite new to NextJS development especially with the App router and am a bit confused.

I am building a fairly simple app with a home page and a contact page.

I have a Nav component for my 'navigation' which consists mainly of a toggle to go from darkmode to lightmode.

My layout.js is almost unchanged


export const metadata = {
  title: "Test",
  description: "My Next Test",
}

const RootLayout = ({ children }) => {
  return (
    <html lang="en">
      <body className="flex flex-col min-h-screen py-3 pl-24 pr-10 bg-black">
        {children}
      </body>
    </html>
  )
}

export default RootLayout

My page.js in the app folder looks like this


import React from "react"
import { useState } from "react"
import { clsx } from "clsx"

import Nav from "../components/Nav"
import Footer from "../components/Footer"
import Search from "@/components/Search"

const Home = () => {
  const [darkMode, setDarkmode] = useState(true)
  const [english, setEnglish] = useState(true)

  const toggleDarkMode = () => {
    setDarkmode(!darkMode)
  }

  const toggleEnglish = () => {
    console.log("toggle english,", english)
    setEnglish(!english)
  }

  return (
    <>
      <Nav
        english={english}
        toggleEnglish={toggleEnglish}
        darkMode={darkMode}
        toggleDarkMode={toggleDarkMode}
      />

      <main
        className={clsx(
          "flex flex-1 flex-col items-start justify-start w-1/2 bg-white dark:bg-black pt-20",
          { dark: darkMode }
        )}
      >
        <h1 className="mb-12 text-3xl text-black dark:text-white">
          Santi van den Toorn
        </h1>
        <p className="mb-8 text-black dark:text-white">
          {english ? (
            <span>
              text
            </span>
          ) : (
            <span>
           text
            </span>
          )}
        </p>
        <Search english={english} />
      </main>

      <Footer />
    </>
  )
}

export default Home

In my contact folder I have a page.js

import React from "react"

const Home = () => {
  return (
    <>
      <h1>contact</h1>
    </>
  )
}

export default Home

My nav component


const Nav = ({ darkMode, english, toggleDarkMode, toggleEnglish }) => {
  return (
    <nav className="flex justify-end w-full h-12 bg-black ">
      {english ? (
        <span
          onClick={toggleEnglish}
          className="mr-2 text-white hover:cursor-pointer"
        >
          NL
        </span>
      ) : (
        <span
          onClick={toggleEnglish}
          className="mr-2 text-white hover:cursor-pointer"
        >
          EN
        </span>
      )}
      {darkMode ? (
        <Sun
          color="white"
          size={24}
          onClick={toggleDarkMode}
          className="hover:cursor-pointer"
        />
      ) : (
        <Moon
          color="white"
          size={24}
          onClick={toggleDarkMode}
          className="hover:cursor-pointer"
        />
      )}
    </nav>
  )
}

export default Nav

I dont get how I can also apply the Nav and footer to the contact page And I need to have the darkmode state in the layout.js to add the 'dark' class to the html element. (I use Tailwind to manage darkmode by selector).

In the past I used to add those stuff to the _app.js file but now I dont get how to elevate the state above the page.js ? I 'ts possibly a stupid question but hope someone can help.

Thanks in advance.

1

There are 1 best solutions below

0
Hashan Hemachandra On

Inside you RootLayout.js file, you need to add you Nav bar and Footer. Because it is file which makes the common design layout. Then you have to pass the children props.

Then set the useState for dark mode and english. Add the 'use client' declarative on the top of the RootLayout so that it can use the useState hook.

RootLayout.js

'use client'

import React, { useState } from 'react';
import './globals.css'; // Your global styles
import Nav from '@/components/Nav';
import Footer from '@/components/Footer';

export const metadata = {
  title: "Test",
  description: "My Next Test",
}

const RootLayout = ({ children }) => {

  const [darkMode, setDarkMode] = useState(true); 
  const [english, setEnglish] = useState(true); 
  
  const toggleDarkMode = () => setDarkMode(!darkMode);
  const toggleEnglish = () => setEnglish(!english);


  return (
    <html lang="en">
      <Nav
        darkMode={darkMode}
        english={english}
        toggleDarkMode={toggleDarkMode}
        toggleEnglish={toggleEnglish}
      />
      <body className="flex flex-col min-h-screen py-3 pl-24 pr-10 bg-black">
        {children}
      </body>
      <Footer />
    </html>
  )
}

export default RootLayout

Now your contact page.js will have the Navbar and Footer.