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?
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,
}