В моем приложении Next.js я не могу получить доступ к window:
Unhandled Rejection (ReferenceError): window is not defined
componentWillMount() {
console.info('window.innerHeight', window.innerHeight);
}



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Переместите код с componentWillMount() на componentDidMount():
componentDidMount() {
console.info('window.innerHeight', window.innerHeight);
}
В Next.js componentDidMount() выполняется только на клиенте, где будут доступны window и другие специфичные для браузера API. Из Next.js вики:
Next.js is universal, which means it executes code first server-side, then client-side. The window object is only present client-side, so if you absolutely need to have access to it in some React component, you should put that code in componentDidMount. This lifecycle method will only be executed on the client. You may also want to check if there isn't some alternative universal library which may suit your needs.
В том же духе componentWillMount() будет устарел в v17 React, поэтому его фактически будет потенциально небезопасно использовать в самом ближайшем будущем.
componentWillMount() Хук жизненного цикла работает как на стороне сервера, так и на стороне клиента. В вашем случае сервер не будет знать о window или document во время обслуживания страницы, предлагается переместить код либо в
Решение 1:
componentDidMount()
Или, решение 2
Если это то, что вы хотите выполнять только в этом случае, вы можете написать что-то вроде:
componentWillMount() {
if (typeof window !== 'undefined') {
console.info('window.innerHeight', window.innerHeight);
}
}
Другое решение является использование ̶p̶r̶o̶c̶e̶s̶s̶.̶b̶r̶o̶w̶s̶e̶r ̶ в выполнении лишь ̶ вашей команды в течение рендер на КЛИЕНТЕ ее стороны.
Но объект process устарел в Webpack5, а также в NextJS, потому что это переменная NodeJS только для серверной части.
Таким образом, мы должны использовать обратный объект window из браузера.
if (typeof window !== "undefined") {
// Client-side-only code
}Другим решением является использование хука реакции для замены componentDidMount:
useEffect(() => {
// Client-side-only code
})этот подход теперь уже используется устарелgithub.com/zeit/next.js/issues/5354#issuecomment-520305040
Вы имеете в виду typeof window !== "undefined", потому что иначе это серверный запуск
серьезно, этому парню нужно отредактировать свой комментарий
@Robbie - я попросил другого «парня» отредактировать комментарий.
Лучший ответ, проверьте этот.
Я разрабатывал веб-сайт в реакции весь день. Первый проект тоже, и я застрял на этом весь день. Спасибо
Без ССР
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
Это работает, даже если библиотека обращается к «окну» во время импорта.
@PeterMortensen, SSR = рендеринг на стороне сервера
как получить доступ к переменной из внешнего js? как var myVar = "bla"
@ bl4ckck, к сожалению, вы можете использовать динамический импорт только для компонента (а не для функций)
TypeError: Cannot call a class as a functionВ конструкторе вашего класса Компонент вы можете добавить
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 = {}
}
}
Это позволит избежать ошибки (в моем случае ошибка произойдет после того, как я нажму кнопку перезагрузки страницы).
есть ли документация по global?
Я настоятельно рекомендую против этого подхода. Настройка global.window на стороне сервера не будет вести себя так же, как фактический объект window, предоставленный в среде браузера.
Если вы используете Реагировать на хуки, вы можете переместить код в Хук Эффекта:
import * as React from "react";
export const MyComp = () => {
React.useEffect(() => {
// window is accessible here.
console.info("window.innerHeight", window.innerHeight);
}, []);
return (<div></div>)
}
Код внутри useEffect выполняется только на клиенте (в браузере), поэтому он имеет доступ к window.
Кажется, это единственный способ сделать это правильно в функциональном компоненте реакции.
Это работает, хотя, если вы делаете что-то внутри useEffect, которое обновляет состояние, обязательно добавьте пустой [] в качестве зависимостей.
Я столкнулся с той же проблемой, когда разрабатывал веб-приложение в next.js. Это устранило мою проблему, вам нужно обратиться к объекту окна в методе жизненного цикла или к хуку реакции. Например, скажем, я хочу создать переменную хранилища с избыточностью, и в этом хранилище я хочу использовать объект Windows, я могу сделать это следующим образом:
let store
useEffect(()=>{
store = createStore(rootReducers, window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__())
}, [])
....
Итак, в основном, когда вы работаете с объектом окна, всегда используйте хук для игры или метод жизненного цикла componentDidMount()
Мне нужно получить доступ к хешу из URL-адреса, поэтому я придумал это
const hash = global.window && window.location.hash;
самое аккуратное решение
это решение тоже работает, и вы можете просто определить его внутри useEffect()
Для таких случаев в Next.js есть Динамический импорт.
Модуль, включающий библиотеку, которая работает только в браузере, рекомендуется использовать динамический импорт. Ссылаться
Ошибка возникает из-за того, что окно еще недоступно, а компонент все еще монтируется. Вы можете получить доступ к объекту окна после того, как компонент смонтирован.
Вы можете создать очень полезный хук для получения динамики 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();
Умная. Очень хорошо.
Это будет работать каждый раз, когда вы изменяете размер окна, это полезно в случаях, когда вы работаете с css -> чтобы ваши страницы реагировали
Дата: 08.06.2021
Проверьте, существует ли объект окна или нет, а затем следуйте коду вместе с ним.
function getSelectedAddress() {
if (typeof window === 'undefined') return;
// Some other logic
}
Вы можете определить переменную состояния и использовать дескриптор события окна для обработки подобных изменений.
const [height, setHeight] = useState();
useEffect(() => {
if (!height) setHeight(window.innerHeight - 140);
window.addEventListener("resize", () => {
setHeight(window.innerHeight - 140);
});
}, []);
Вот простой в использовании обходной путь, который я сделал.
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", потому что если вы просто проверите, что окно не является неопределенным, оно не будет работать, если ваша страница была перенаправлена на, оно просто срабатывает один раз при загрузке. Но этот обходной путь работает, даже если страница была перенаправлена, а не только один раз во время загрузки.
Это будет переопределять window.onload каждый раз
@OwnageIsMagic нет, если вы видите, он устанавливает window.onload, только если страница не загружена.
рассмотрите этот фрагмент runOnClient(f1); runOnClient(f2)
также читайте об этом stackoverflow.com/questions/2414750/…
@OwnageIsMagic Я добавил слушателя, надеюсь, теперь это исправлено.
Я хочу оставить этот подход, который показался мне интересным, для будущих исследователей. Он использует специальный хук useEventListener, который можно использовать во многих других случаях.
Обратите внимание, что вам нужно будет внести небольшое изменение в исходное сообщение, как я предлагаю здесь.
Таким образом, это закончится так:
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])
}
Лучшее решение
import dynamic from 'next/dynamic';
const Chart = dynamic(()=> import('react-apexcharts'), {
ssr:false,
})Ваш ответ может быть улучшен с помощью дополнительной вспомогательной информации. Пожалуйста, редактировать добавьте дополнительную информацию, например цитаты или документацию, чтобы другие могли подтвердить правильность вашего ответа. Дополнительную информацию о том, как писать хорошие ответы, можно найти в справочном центре.
Означает ли это, что эта страница будет отображаться в браузере, а не на сервере? для меня вся цель использования next js - это рендеринг на сервере
Если это приложение NextJS и внутри _document.js, используйте ниже:
<script dangerouslySetInnerHTML = {{
__html: `
var innerHeight = window.innerHeight;
`
}} />
Переместите код в componentDidMount(), который выполняется только на клиенте, где доступен with
window. Кроме того,componentWillMount()является устарел в v17https://github.com/zeit/next.js/wiki/FAQ#i-use-a-library-what-throws-window-is-undefined