如何在网站渲染之前检查React/Gastsby中的window.innerWidth



在我在盖茨比创建的网站上,我想在第一次渲染DOM window.innerWidth之前检查它的大小。我想使用innerWidth的条件检查来决定网站应该如何呈现:桌面版还是移动版。一个简单的修复方法是在创建react组件之前检查窗口的宽度,并在代码中进一步使用true/false值。它在开发版本中有效,但。。。情况是,在生产版本中,当我进行gatsby-build时,我在控制台中收到一个错误:

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;

我已经尝试使用组件WillMount,它运行良好,但已被弃用并标记为不安全。如果我检查componentDidMount中的window.innerWidth没有正确渲染。

我的代码:

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

使用Gatsby,您必须检查浏览器全局变量(如documentwindow(的可用性,因为在您的代码编译并请求这些变量时,它们可能尚未声明/可用。

来自Gatsby文档:

您的一些代码引用了"浏览器全局",如windowdocument。如果这是你的问题,你应该看到上面的错误,比如"未定义窗口"。要解决此问题,请查找有问题的代码并a(如果定义了窗口,则在调用代码之前进行检查Gatsby正在构建时代码未运行(请参阅下面的代码示例(,或者b( 如果代码在React.js组件的render函数中,请移动该代码进入CCD_ 5生命周期或CCD_,它确保代码不会运行,除非它在浏览器中

因此,每次检查window时,都必须添加:

if(typeof window !== undefined){
//your stuff
}

应用于您的代码:

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 });
}
}
};
};

当然,应该重构上面的代码以避免条件的重复,例如,在触发事件之前添加window条件。

您可以在回调中包装获取窗口宽度,因此添加函数getWindowWidth,返回实际窗口宽度。

在检查window是否首先以这种方式定义后,尝试执行window.innerWidth

componentDidMount() {
if (typeof window !== 'undefined') {
window.addEventListener('resize', this.onResize)
}
}
componentWillUnmount() {
if (typeof window !== 'undefined') {
window.removeEventListener('resize', this.onResize)
}
}

最新更新