Reputation: 124
On the website I create in Gatsby I would like to check the size of the DOM window.innerWidth before it will be first rendered. I would like to use a conditional check of innerWidth to decide how the website should be rendered: as desktop or mobile version. A simple fix for that would be to check the width of the window before creating react component and use the true/false value further in the code. It works in development version but... The case is that in production version when I do gatsby build, I get an error in console:
failed Building static HTML for pages - 2.872s
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
> 30 | const sizeOfWindow = window.innerWidth;
I tried already to use componentWillMount which works fine but it is deprecated and marked as unsafe. If I check the window.innerWidth in componentDidMount doesn't render properly.
My code:
interface IndexPageState {
isDesktop: boolean;
windowWidth: number;
}
class IndexPage extends React.Component<any, IndexPageState> {
constructor(props: any) {
super(props);
this.state = {
windowWidth: 0,
isDesktop: true,
};
}
componentWillMount(): void {
this.onResize();
}
onResize = () => {
if (!(this.state.windowWidth >= 769)) {
this.setState({ isDesktop: false });
} else {
this.setState({ isDesktop: true });
}
};
componentDidMount = () => {
this.setState({ windowWidth: window.innerWidth });
if (!(this.state.windowWidth >= 769)) {
this.setState({ isDesktop: false });
} else {
this.setState({ isDesktop: true });
}
window.addEventListener('resize', this.onResize);
};
componentWillUnmount = () => {
window.removeEventListener('resize', this.onResize);
};
render() {
const { isDesktop, windowWidth } = this.state;
return (
<>
<SEO title="Home" />
<div className={styles.App}>
Upvotes: 0
Views: 2372
Reputation: 29335
With Gatsby, you must check for the availability of the browser global variables like document
or window
, since at the time your code is compiling and asking for those variables, they may not be declared/available yet.
From the Gatsby documentation:
Some of your code references “browser globals” like
window
ordocument
. If this is your problem you should see an error above like “window is not defined”. To fix this, find the offending code and either a) check before calling the code if window is defined so the code doesn’t run while Gatsby is building (see code sample below) or b) if the code is in the render function of a React.js component, move that code into acomponentDidMount
lifecycle or into auseEffect
hook, which ensures the code doesn’t run unless it’s in the browser
So, every time you check for the window
, you must add:
if(typeof window !== undefined){
//your stuff
}
Applied to your code:
componentDidMount = () => {
if(typeof window !== undefined){
this.setState({ windowWidth: window.innerWidth });
if (!(this.state.windowWidth >= 769)) {
this.setState({ isDesktop: false });
} else {
this.setState({ isDesktop: true });
}
window.addEventListener('resize', this.onResize);
}
};
componentWillUnmount = () => {
if(typeof window !== undefined){
window.removeEventListener('resize', this.onResize);
}
onResize = () => {
if(typeof window !== undefined){
if (!(this.state.windowWidth >= 769)) {
this.setState({ isDesktop: false });
} else {
this.setState({ isDesktop: true });
}
}
};
};
Of course, the code above should be refactored to avoid the repetition of the condition, by adding the window
condition before the event is triggered for example.
Upvotes: 1
Reputation: 2720
Try to execute window.innerWidth
after checking the window
is defined first in this way.
componentDidMount() {
if (typeof window !== 'undefined') {
window.addEventListener('resize', this.onResize)
}
}
componentWillUnmount() {
if (typeof window !== 'undefined') {
window.removeEventListener('resize', this.onResize)
}
}
Upvotes: 1
Reputation: 2406
You can wrap getting the window width in the callback, so add function getWindowWidth
where you will return the actual window width.
Upvotes: 1