在我的Next.js应用程序中,我似乎无法访问窗口:

未处理的拒绝(ReferenceError):没有定义窗口

componentWillMount() {
    console.log('window.innerHeight', window.innerHeight);
}


当前回答

这是我做过的一个简单的解决方法。

const runOnClient = (func: () => any) => {
  if (typeof window !== "undefined") {
    if (window.document.readyState == "loading") {
      window.addEventListener("load", func);
    } else {
      func();
    }
  }
};

用法:

runOnClient(() => {
// access window as you like
})

// or async
runOnClient(async () => {
// remember to catch errors that might be raised in promises, and use the `await` keyword wherever needed
})

这比typeof window !== "undefined"要好,因为如果你只是检查窗口不是undefined,如果你的页面被重定向到,它不会工作,它只在加载时工作一次。但是,即使页面被重定向到,这个解决方法也可以工作,而不仅仅是在加载时一次。

其他回答

如果它是NextJS应用,并且在_document.js中,使用下面的方法:

<script dangerouslySetInnerHTML={{
        __html: `
            var innerHeight = window.innerHeight;
        `
        }} />

当我在next.js中开发web应用程序时,我也面临着同样的问题,这解决了我的问题,你必须在生命周期方法或react Hook中引用引用窗口对象。例如,假设我想用redux创建一个存储变量,在这个存储中我想使用一个windows对象,我可以这样做:

let store
useEffect(()=>{
    store = createStore(rootReducers,   window.__REDUX_DEVTOOLS_EXTENSION__ && 
    window.__REDUX_DEVTOOLS_EXTENSION__())
 }, [])
 ....

所以基本上,当你使用window的对象时,总是使用钩子来玩或者componentDidMount()生命周期方法

如果你使用React Hooks,你可以将代码移动到Effect Hook中:

import * as React from "react";

export const MyComp = () => {

  React.useEffect(() => {
    // window is accessible here.
    console.log("window.innerHeight", window.innerHeight);
  }, []);

  return (<div></div>)
}

useEffect中的代码只在客户端(在浏览器中)执行,因此它可以访问window。

发生错误是因为窗口尚未可用,而组件仍在挂载。组件挂载后,可以访问窗口对象。

您可以创建一个非常有用的钩子来获取动态窗口。innerHeight或window.innerWidth

const useDeviceSize = () => {

  const [width, setWidth] = useState(0)
  const [height, setHeight] = useState(0)

  const handleWindowResize = () => {
    setWidth(window.innerWidth);
    setHeight(window.innerHeight);
  }

  useEffect(() => {
    // component is mounted and window is available
    handleWindowResize();
    window.addEventListener('resize', handleWindowResize);
    // unsubscribe from the event on component unmount
    return () => window.removeEventListener('resize', handleWindowResize);
  }, []);

  return [width, height]

}

export default useDeviceSize 

用例:

const [width, height] = useDeviceSize();

“嗡�̶b̶r̶o̶w̶s̶e̶r̶ ̶t̶ ̶j̶u̶s̶t̶ ̶e̶x̶e̶c̶u̶t̶e̶ ̶y̶o̶u̶r̶ ̶c̶o̶m̶m̶a̶n̶d̶d̶u̶r̶n̶n̶ ̶r̶̶n̶n̶ ̶o̶n̶ ̶t̶ ̶c̶l̶i̶e̶n̶ ̶s̶i̶d̶e̶ ̶o̶n̶l̶y̶。

但是process object在Webpack5和NextJS中已经被弃用了,因为它是一个仅用于后端的NodeJS变量。

我们必须使用浏览器中的backwindow对象。

If (typeof window !== "undefined") { //客户端代码 }

其他解决方案是使用react钩子替换componentDidMount:

useEffect(() => { //客户端代码 })