Next js window.matchMedia prefers-color-scheme window is not defined

1.7k views Asked by At

I am using React.js with Next.js, and I have the following problem. When the page is loaded, I have to set a variable which should tell me if user is using dark mode or not.

I did the following, but I'm not sure if it's correct.

I had to set a value, because if I use window inside useState without using useEffect, it gives me problems with Next.js.

const [darkMode, setDarkMode] = useState(false);

useEffect(() => {
  setDarkMode(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)
  const modeMe = (e) => {
    setDarkMode(!!e.matches);
  }
  window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', modeMe);
  return window.matchMedia('(prefers-color-scheme: dark)').removeListener(modeMe);
}, []);

or

const useDeviceMode = () => {
  const [darkMode, setDarkMode] = useState(false);
  useEffect(() => {
    setDarkMode(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)
    const modeMe = e => { setDarkMode(!!e.matches); }
    window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', modeMe);
    return window.matchMedia('(prefers-color-scheme: dark)').removeListener(modeMe);
  }, []);
  return [darkMode, setDarkMode]
}

const [darkMode, setDarkMode] = useDeviceMode();

Can you give me some advice?

1

There are 1 answers

0
Masterpage On

Consider this snippet—

const [darkMode, setDarkMode] = useState(false);

const modeMe = (e) => {
    setDarkMode(!!e.matches);
  };

useEffect(() => {
  const matchMedia = window.matchMedia("(prefers-color-scheme: dark)");
  
  setDarkMode(matchMedia.matches);
  matchMedia.addEventListener("change", modeMe);

  return () => matchMedia.removeEventListener("change", modeMe);
}, []);

Even better, come up with this custom hook—

import { useEffect, useState } from 'react';

const useDarkMode = () => {
  const [darkMode, setDarkMode] = useState(false);

  const modeMe = (e) => {
    setDarkMode(!!e.matches);
  };

  useEffect(() => {
    const matchMedia = window.matchMedia("(prefers-color-scheme: dark)");

    setDarkMode(matchMedia.matches);
    matchMedia.addEventListener("change", modeMe);

    return () => matchMedia.removeEventListener("change", modeMe);
  }, []);

  return darkMode;
};