use-dark-mode icon indicating copy to clipboard operation
use-dark-mode copied to clipboard

Is there any way to implement useDarkMode config static or server-side? (NextJS)

Open tendan opened this issue 3 years ago • 5 comments

I'm trying to implement the configuration for useDarkMode hook, it works when NextJS uses CSR, but has an error when renders in server-side. Any way to implement that configuration in SSG or SSR? Also i want to use the element for <html> anchor tag, because of using Tailwind CSS, so it's crucial for me to implement element attribute.

My code:

function MyApp({ Component, pageProps }: AppProps) {
  useEffect(() => {
    // @ts-ignore
    const darkMode = useDarkMode(false, {
      classNameDark: "dark",
      classNameLight: "light",
      element: document.getElementsByTagName("html")[0]
    });
  }, [])


  return (
    <Fragment>
      <Head>
        <title>Oficjalna strona Nostalgawki</title>
        <meta name="viewport" content="initial-scale=1, width=device-width"/>
      </Head>
      <div className={"main"}>
        <AnimatePresence exitBeforeEnter>
            <Navbar key={"navbar"}/>
            <Component key={"component"} {...pageProps} />
            <Footer key={"footer"}/>
        </AnimatePresence>
      </div>
    </Fragment>
  );
}

tendan avatar Dec 04 '20 15:12 tendan

Great question, I'd be interested to see what the resolution here is. This is a great package.

El vie., 4 de diciembre de 2020 10:43 a. m., TenDan < [email protected]> escribió:

I'm trying to implement the configuration for useDarkMode hook, it works when NextJS uses CSR, but has an error when renders in server-side. Any way to implement that configuration in SSG or SSR? Also i want to use the element for anchor tag, because of using Tailwind CSS, so it's crucial for me to implement element attribute.

My code:

function MyApp({ Component, pageProps }: AppProps) { useEffect(() => { // @ts-ignore const darkMode = useDarkMode(false, { classNameDark: "dark", classNameLight: "light", element: document.getElementsByTagName("html")[0] }); }, [])

return ( <Fragment> <Head>

Oficjalna strona Nostalgawki </Head> <div className={"main"}> <AnimatePresence exitBeforeEnter> <Navbar key={"navbar"}/> <Component key={"component"} {...pageProps} /> <Footer key={"footer"}/> </AnimatePresence> </Fragment> ); }

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/donavon/use-dark-mode/issues/64, or unsubscribe https://github.com/notifications/unsubscribe-auth/AMV42QRFRTTBM7MIN6N22LTSTD7RRANCNFSM4UNTJMJA .

djD-REK avatar Dec 06 '20 17:12 djD-REK

Also running into the same issue. What are your thoughts on this @donavon ?

vacekj avatar Dec 17 '20 17:12 vacekj

@TenDan useDarkMode (or any hook for that matter) can NOT be used inside of a useEffect hook. There's also no need.

As to using html instead, you can always specify an onChange handler and do the work yourself.

For example:

  const { value } = useDarkMode(false, { 
    onChange: (state: boolean)  => {
      const htmlElement = document.documentElement;
      if (state) {
        htmlElement.classList.add('dark');
        htmlElement.classList.remove('light');
      } else {
        htmlElement.classList.add('light');
        htmlElement.classList.remove('dark');
      }
    }
  });

donavon avatar Dec 18 '20 15:12 donavon

Can you give a short example of this failing in SSR that I can clone and run locally?

donavon avatar Dec 18 '20 15:12 donavon

Hey!

Since the localStorage variable doesn't really exist during SSR, the hook might have some unintended behavior.

I managed to get it working well by using use-ssr.

// ...other imports
import { useSSR } from "use-ssr"

// Prints whether to dark mode is on / off
const DarkThemeTruthy = () => {
  // Get theme value
  const { value } = useDarkMode(false, {
    classNameDark: "dark",
    classNameLight: "light",
    storageKey: "dark-theme",
  })

  // Get rendering mode
  const { isBrowser } = useSSR()

  return <Fragment>{isBrowser && <div>{value}</div>}</Fragment>
}

I've tested this on a Gatsby site, using both React and Preact. It works quite well but there is one caveat. Since useSSR is being used, the <div> is Client Side Rendered.

Hope this helps!

kelvindecosta avatar Mar 06 '21 06:03 kelvindecosta