代码之家  ›  专栏  ›  技术社区  ›  Leon Gaban

NextJS React app中未定义窗口?

  •  0
  • Leon Gaban  · 技术社区  · 6 年前

    在我的 Next.js 我似乎无法访问应用程序 window :

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

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

    Enter image description here

    0 回复  |  直到 5 年前
        1
  •  124
  •   Darryl RN    3 年前

    另一个解决方案是使用 p̶r̶o̶c̶e̶s̶s̶.̶b̶r̶o̶w̶s̶e̶r (204月月)双方的研究者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者者在美国的研究者者们的周四周四周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五周五eÌÌoÌnÌlÌyÌ。

    但是 process 对象在Webpack5和NextJS中已被弃用,因为它是仅用于后端的NodeJS变量。

    所以我们必须使用back window 对象从浏览器中删除。

    if (typeof window !== "undefined") {
      // Client-side-only code
    }

    另一种解决方案是使用react钩子替换 componentDidMount :

    useEffect(() => {
        // Client-side-only code
    })
        2
  •  83
  •   Alan W. Smith vishes_shell    3 年前

    将代码从 componentWillMount() componentDidMount() :

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

    下一个。js, componentDidMount() 仅在客户端上执行,其中 window 以及其他特定于浏览器的API。从 Next.js wiki :

    下一个js是通用的,这意味着它首先在服务器端执行代码, 然后是客户端。窗口对象只在客户端出现,所以如果 你绝对需要在某个组件中访问它,你 应该把代码放在componentDidMount中。这种生命周期方法将 只能在客户端执行。你可能还想检查一下 没有其他适合你需要的通用图书馆。

    同样的道理, 组件willmount() deprecated 在React的v17中,因此在不久的将来使用它可能会非常不安全。

        3
  •  78
  •   Dylan Pierce    5 年前

    如果你使用 反应钩 你可以把代码移到 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 .

        4
  •  57
  •   tanguy_k streuspeicher    4 年前

    没有SSR

    https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr

    import dynamic from 'next/dynamic'
    
    const DynamicComponentWithNoSSR = dynamic(
      () => import('../components/hello3'),
      { ssr: false }
    )
    
    function Home() {
      return (
        <div>
          <Header />
          <DynamicComponentWithNoSSR />
          <p>HOME PAGE is here!</p>
        </div>
      )
    }
    
    export default Home
    
        5
  •  12
  •   3limin4t0r    5 年前

    componentWillMount() lifecycle hook既可以在服务器端工作,也可以在客户端工作。在您的情况下,服务器不会知道 window document 在页面服务期间,建议将代码移动到

    解决方案1:

    componentDidMount()
    

    或者,解决方案2

    如果你只想在里面表演,那么你可以写下:

    componentWillMount() {
        if (typeof window !== 'undefined') {
            console.log('window.innerHeight', window.innerHeight);
        }
    }
    
        6
  •  9
  •   Peter Mortensen icecrime    5 年前

    在类的构造函数中 组成部分 你可以加上

    if (typeof window === 'undefined') {
        global.window = {}
    }
    

    例子:

    import React, { Component } from 'react'
    
    class MyClassName extends Component {
    
        constructor(props){
            super(props)
            ...
            if (typeof window === 'undefined') {
                global.window = {}
            }
    }
    

    这将避免错误(在我的情况下,错误将在我单击页面的重新加载后发生)。

        7
  •  6
  •   Ismoil Shokirov    3 年前

    发生错误的原因是,当组件仍在安装时,窗口还不可用。安装组件后,可以访问窗口对象。

    你可以创建一个非常有用的钩子来获得动态 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();
    
        8
  •  5
  •   U.A    4 年前

    我必须从URL访问哈希,所以我想到了这个

    const hash = global.window && window.location.hash;
    
        9
  •  3
  •   crispengari    4 年前

    在next开发web应用程序时,我也面临同样的问题。js 这解决了我的问题,您必须在生命周期方法或react钩子中引用窗口对象。例如,假设我想用redux创建一个store变量,在这个store中,我想使用一个windows对象,我可以如下所示:

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

    所以,基本上,当你在处理窗口的对象时,总是使用一个钩子来玩或玩 componentDidMount() 生命周期法

        10
  •  3
  •   Vinicius Pollo    3 年前

    有史以来最好的解决方案

    import dynamic from 'next/dynamic';
    
    const Chart = dynamic(()=> import('react-apexcharts'), {
        ssr:false,
    })
        11
  •  2
  •   Roj    3 年前

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

    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" ,因为如果你只是检查窗口是否未定义,如果你的页面被重定向到,它将不工作,加载时只工作一次。但是,即使页面被重定向到,这种变通方法仍然有效,而不是在加载时只重定向一次。

        12
  •  1
  •   San-Mak    4 年前

    对于这种情况,下一步。js有 Dynamic Import .

    如果一个模块包含一个只在浏览器中工作的库,建议使用动态导入。 Refer

        13
  •  1
  •   Mohamed Jakkariya    3 年前

    日期:2021年8月6日

    检查窗口对象是否存在,然后按照代码进行操作。

     function getSelectedAddress() {
        if (typeof window === 'undefined') return;
    
        // Some other logic
     }
    
        14
  •  1
  •   Parsa Safavi    3 年前

    有点晚,但你也可以考虑使用 Dynamic Imports 从…起 next 关掉 SSR 对于该组件。

    可以在动态函数中扭曲组件的导入,然后将返回的值用作实际组件。

    import dynamic from 'next/dynamic'
    
    const BoardDynamic = dynamic(() => import('../components/Board.tsx'), {
      SSR: false,
    })
    
    
    <>
       <BoardDynamic />
    </>
    
        15
  •  0
  •   Seth Samuel    3 年前

    您可以定义一个状态变量,并使用窗口事件句柄来处理这样的更改。

    const [height, setHeight] = useState();
    
    useEffect(() => {
        if (!height) setHeight(window.innerHeight - 140);
        window.addEventListener("resize", () => {
            setHeight(window.innerHeight - 140);
        });
    }, []);
    
        16
  •  0
  •   Lakshit Nagar    3 年前

    如果是NextJS应用程序和内部 _文件。js ,请在下面使用:

    <script dangerouslySetInnerHTML={{
            __html: `
                var innerHeight = window.innerHeight;
            `
            }} />
    
        17
  •  -1
  •   Lianel    3 年前

    我想留给未来的研究人员一个有趣的方法。它使用了一个定制的钩子 useEventListener 这可以用于其他许多需求。

    请注意,您需要对最初发布的内容进行一些更改,就像我建议的那样 here .

    所以它会这样结束:

    import { useRef, useEffect } from 'react'
    
    export const useEventListener = (eventName, handler, element) => {
      const savedHandler = useRef()
    
      useEffect(() => {
        savedHandler.current = handler
      }, [handler])
    
      useEffect(() => {
        element = !element ? window : element
        const isSupported = element && element.addEventListener
        if (!isSupported) return
    
        const eventListener = (event) => savedHandler.current(event)
    
        element.addEventListener(eventName, eventListener)
    
        return () => {
          element.removeEventListener(eventName, eventListener)
        }
      }, [eventName, element])
    }