0

After deployment to server and testing in Gatsby with gatsby clean && gatsby build && gatsby serve whenever root (https://foobar.com/) is visited anything that relies on my ThemeProvider for dimensions doesn't render correctly.

After debugging I've isolated my issue down to how my useState is hard set with a value of 0:

 const [size, setSize] = useState({
    windowWidth: hasWindow ? window.innerWidth : 0,
    windowHeight: hasWindow ? window.innerHeight : 0,
  })

full code:

import { useState, useEffect } from 'react'

const hasWindow = typeof window !== 'undefined'

const useWindowDimensions = () => {
  const [size, setSize] = useState({
    windowWidth: hasWindow ? window.innerWidth : 0,
    windowHeight: hasWindow ? window.innerHeight : 0,
  })

  const updateSize = () =>
    setSize({
      windowWidth: window.innerWidth,
      windowHeight: window.innerHeight,
    })

  useEffect(() => (window.onresize = updateSize), [])

  return size
}

export default useWindowDimensions

which gets passed to my ThemeProvider:

import React, { createContext } from 'react'

// Utils
import useWindowDimensions from '../utils/useWindowDimensions'

const defaultContext = {
  windowWidth: 0,
  windowHeight: 0,
}

export const ThemeContext = createContext(defaultContext)

const ThemeProvider = ({ children }) => {
  const { windowWidth, windowHeight } = useWindowDimensions()

  return (
    <ThemeContext.Provider value={{ windowWidth, windowHeight }}>{children}</ThemeContext.Provider>
  )
}

export default ThemeProvider

and if I hard set my useState values:

  const [size, setSize] = useState({
    windowWidth: hasWindow ? window.innerWidth : 1600,
    windowHeight: hasWindow ? window.innerHeight : 1600,
  })

my site renders fine in the browser but this is technically wrong if viewed with a mobile device or the browser is smaller than 1600px. Whenever I navigate to anywhere else in the site the useState is updated and there isn't an issue.

Omitting the ternary check for window and hard setting useState to:

const [size, setSize] = useState({
  windowWidth: window.innerWidth,
  windowHeight: window.innerHeight,
})

produces an expected server rendering error:

"window" is not available during server side rendering.

after gatsby build.

How should I be setting my useState window dimensions after server load so that my site will pass the correct values to the ThemeProvider and render everything correctly when root is visited?

DᴀʀᴛʜVᴀᴅᴇʀ
  • 7,681
  • 17
  • 73
  • 127

1 Answers1

0

Please try this slight modification and let me know if that works. In your useWindowDimensions custom hook:

import { useState, useEffect } from 'react'

const useWindowDimensions = () => {
  const [size, setSize] = useState({
    windowWidth: undefined,
    windowHeight: undefined
  })

  const updateSize = () =>
    setSize({
      windowWidth: window.innerWidth,
      windowHeight: window.innerHeight,
    })

  useEffect(() => {
    window.addEventListener("resize", updateSize);
    updateSize();

    return () => window.removeEventListener("resize", updateSize);
  }, [])

  return size
}

export default useWindowDimensions

Your Context:

const defaultContext = {
  windowWidth: undefined,
  windowHeight: undefined,
}
DᴀʀᴛʜVᴀᴅᴇʀ
  • 7,681
  • 17
  • 73
  • 127
ivanatias
  • 3,105
  • 2
  • 14
  • 25