Published on

The window object, React hooks, and GatsbyJS

Last Modified on
Last modified on
Authors
The window object, React hooks, and GatsbyJS
Photo by Meg on Unsplash

This past Friday I added a Crisp chat box to interglobalmedianetwork.com. Afterwards, I visited the website on mobile, and noticed that my ScrollUpButton was not well positioned as a result of the new chat box when the browser window was < 560px wide.

This really bothered me, and I wanted to fix it. The problem was, however, that I use inline styling inside the ScrollUpButton component and didn't know how I could add media queries to inline styling in React.

In my regular JSX, I use styled-components and am able to add media queries to those styles easily and in the same way as I would in CSS or SCSS. But inline styles inside a component element is another story.

I started googling for answers, and came across the following very interesting solution:

I haven't had the time or chance to get too much into React hooks, so I found this opportunity to use them in this instance very exciting!

Based on the article, I came up with the following re-usable hook called useMediaQuery which I stored in a folder called hooks in my src folder and placed the hook in a file called mediaQueryHooks.js:

import { useEffect, useState } from 'react'
import { window } from 'browser-monads'

export const useMediaQuery = (query) => {
	const mediaMatch = window.matchMedia(query)
	const [matches, setMatches] = useState(mediaMatch.matches)

	useEffect(() => {
		const handler = (e) => setMatches(e.matches)
		mediaMatch.addListener(handler)
		return () => mediaMatch.removeListener(handler)
	})
	return matches
}

Then I imported the hook into my Footer.js component and my index.js home page:

// Footer.js
import { useMediaQuery } from '../../hooks/mediaQueryHooks'

// index.js
import { useMediaQuery } from '../hooks/mediaQueryHooks'

I used the hook in Footer.js:


const styles = {
    container: (notRightMargin, marginBottomLess) => ({
        background: 'transparent',
        outline: 'none',
        marginBottom: marginBottomLess ? '3rem' : '3.75rem',
        marginRight: notRightMargin ? '-0.25rem' : '0.5rem',
    }),
}

const Footer = () => {
    const notRightMargin = useMediaQuery('(max-width: 559px)')
    const marginBottomLess = useMediaQuery('(max-width: 559px)')
    return (
    ...
    <ScrollUpButton
    style={styles.container(notRightMargin, marginBottomLess)}
    ContainerClassName="ScrollUpButton__Container"
    />
    ...
    )
}

as well as index.js:


const styles = {
    container: (notRightMargin, marginBottomLess) => ({
        background: 'transparent',
        outline: 'none',
        marginBottom: marginBottomLess ? '3rem' : '3.75rem',
        marginRight: notRightMargin ? '-0.25rem' : '0.5rem',
    }),
}

const IndexPage = props => {
    ...
    const notRightMargin = useMediaQuery('(max-width: 559px)')
    const marginBottomLess = useMediaQuery('(max-width: 559px)')
    return (
    ...
    <ScrollUpButton
    style={styles.container(notRightMargin,marginBottomLess)}
    ContainerClassName="ScrollUpButton__Container"
    />
    ...
    )
}

Then I ran

npx gatsby develop

and everything rendered as it should in the browser window when it was < 560px wide. But when I ran

npx gatsby build

I got the following errors in Command Line:

npx gatsby build                                                   ⏎ ✹ ✭
success open and validate gatsby-configs - 0.083s
success load plugins - 1.829s
success onPreInit - 0.009s
success delete html and css files from previous builds - 0.029s
success initialize cache - 0.008s
success copy gatsby files - 0.235s
success onPreBootstrap - 0.017s
success createSchemaCustomization - 0.007s
success source and transform nodes - 0.601s
success building schema - 0.518s
success createPages - 0.226s
success createPagesStatefully - 0.201s
success onPreExtractQueries - 0.002s
success update schema - 0.061s
success extract queries from components - 0.639s
success write out requires - 0.008s
success write out redirect data - 0.003s
success Build manifest and related icons - 0.125s
success onPostBootstrap - 0.160s

info bootstrap finished - 8.431 s

warn "export 'windowSize' was not found in '../../hooks/windowHooks'
warn "export 'windowSize' was not found in '../../hooks/windowHooks'
success Building production JavaScript and CSS bundles - 22.721s
success Rewriting compilation hashes - 0.004s
success run queries - 25.615s - 207/207 8.08/s
failed Building static HTML for pages - 3.727s

 ERROR #95312

"window" is not available during server side rendering.

See our docs page for more info on this error: https://gatsby.dev/debug-html

2 |
3 | export const useMediaQuery = (query) => {
> 4 | const mediaMatch = window.matchMedia(query);
|             ^
5 |   const [matches, setMatches] = useState(mediaMatch.matches);
6 |     useEffect(() => {
7 |         const handler = e => setMatches(e.matches);

WebpackError: ReferenceError: window is not defined

- mediaQueryHooks.js:4 useMediaQuery
src/hooks/mediaQueryHooks.js:4:24

- Footer.js:160 Footer

src/components/Footer/Footer.js:160:42

I tried all sorts of solutions which I came across on the GatsbyJS repo and elsewhere which I won't even get into here, because they were useless and just created even more errors.

Then I googled again for the window object as not being defined in Gatsby using React hooks. I don't remember the exact words I used this time, but this was the only time I ended up with the right search result. This is what I came up with:

Jensen Bernard writes about the npm package he created called browser-monads in response to this error he also received in GatbsyJS.

All I had to do was import it into mediaQueryHooks.js where my useMediaQuery React hook resides.

// mediaQueryHooks.js
import { window } from 'browser-monads'

When I ran npx gatsby build again, it was successful! And when I deployed the changes to Netlify, the deployment to remote was successful as well!

And that was it!

I will be embedding this episode of Plugging in The Holes along with a transcript in the form of a post on interglobalmedianetwork.com for your hearing and reading pleasure. I will be including the related resource links mentioned in the podcast of course. Always do. Bye for now!