donavon / use-dark-mode

A custom React Hook to help you implement a "dark mode" component.
MIT License
1.28k stars 100 forks source link

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

Open tendan opened 3 years ago

tendan commented 3 years ago

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>
  );
}
djD-REK commented 3 years ago

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 < notifications@github.com> 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 (

Oficjalna strona Nostalgawki

); }

— 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 .

vacekj commented 3 years ago

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

donavon commented 3 years ago

@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 commented 3 years ago

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

kelvindecosta commented 3 years ago

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!