window.matchMedia is not a function

Viewed 2801

I have some problem with window global object on build project in gatsby. I use custom media hook for change login in some resolutions. It's work fine when project running. But when i try npm run build for build project Webpack gives error : WebpackError: TypeError: window.matchMedia is not a function

  const useMedia = (query) => {
    const windowGlobal = typeof window !== 'undefined' && window
    const [matches, setMatches] = useState(windowGlobal.matchMedia(query).matches)
    useEffect(() => {
      const media = windowGlobal.matchMedia(query)
      if (media.matches !== matches) setMatches(media.matches)
      const listener = () => setMatches(media.matches)
      media.addEventListener('change', listener)
      return () => media.removeEventListener('change', listener)
    }, [matches, query])

    return matches
  }
  const match = useMedia('(max-width: 575px)')
  const changeLabel = match ? 'Cancel' : 'Add Now'
2 Answers

Try:

 const useMedia = (query) => {
    const [matches, setMatches] = useState(typeof window !=='undefined' && window.matchMedia(query).matches);

    useEffect(() => {
      const media = windowGlobal.matchMedia(query)
      if (media.matches !== matches) setMatches(media.matches)
      const listener = () => setMatches(media.matches)
      media.addEventListener('change', listener)
      return () => media.removeEventListener('change', listener)
    }, [matches, query])

    return matches
  }
  const match = useMedia('(max-width: 575px)')
  const changeLabel = match ? 'Cancel' : 'Add Now'

You were fixing the value of windowMedia (same as isBrowser) with a const and the state was trying to set a value of undefined at the time that the window was not set, you can simplify by setting the state only when the window is defined.

You're doing it wrong. You're setting the const windowGlobal to be true/false and then use it in useState(windowGlobal...) which means windowGlobal is a bool and not a function. Use window directly like my example below:

const windowGlobal = typeof window !== 'undefined' && window
const [matches, setMatches] = useState(windowGlobal.matchMedia(query).matches)

Id go with making an if window is set, then execute the code.

const useMedia = (query) => {
  const [matches, setMatches] = useState(windowGlobal.matchMedia(query).matches)
  
  const isBrowser = () => typeof window !== 'undefined' && window;
  
  useEffect(() => {
    if (isBrowser()) {
      const media = window.matchMedia(query)
      if (media.matches !== matches) setMatches(media.matches)
      const listener = () => setMatches(media.matches)
      media.addEventListener('change', listener)

      return () => media.removeEventListener('change', listener)
    }
  }, [matches, query])

  return matches
}
const match = useMedia('(max-width: 575px)')
const changeLabel = match ? 'Cancel' : 'Add Now'
Related