Что будет при обращении к DOM элементам или браузерным API на сервере
Что проверяют
Понимаете ли вы, что один и тот же код исполняется в двух разных средах, и знаете ли, как это чинят в приложении с серверным рендерингом. Ответ показывает, работали ли вы с реальным SSR или только с одностраничным приложением.
Как отвечать
На сервере нет ни window, ни document, ни localStorage, ни navigator. Обращение к ним даёт ReferenceError: document is not defined, и падает это не у пользователя в браузере, а на рендере или на сборке: страница отдаёт ошибку сервера либо билд не проходит вовсе.
Что стоит сказать дальше:
- момент падения зависит от места. Обращение к
windowна верхнем уровне модуля выполнится уже при импорте, внутри рендера при рендере, а внутриuseEffectне выполнится на сервере никогда, потому что эффекты там не запускаются; - если компонент без браузера принципиально не работает, его подключают динамическим импортом с выключенным серверным рендерингом, а не обвешивают проверками;
- проверка
typeof window !== "undefined"прямо в разметке опасна отдельно. Серверный и первый клиентский рендер обязаны совпасть, иначе будет ошибка гидратации и мигающий интерфейс. Правильно завести состояние, которое становится истинным в эффекте, и ветвиться по нему; - не всё браузерное отсутствует на сервере:
fetch,URL,TextEncoder,crypto.randomUUIDв современном Node есть.
Где спотыкаются
Считают, что на сервере недоступно всё, что привыкли звать браузерным, и тащат в проект полифилл сетевого запроса. Список отсутствующего конечен и сводится к DOM и к тому, что связано с окном и вкладкой.
Второе: лечат проверкой на window прямо в возвращаемой разметке. Ошибка исчезает, вместо неё появляется расхождение разметки при гидратации, которое ловится куда труднее исходной.
Третье: читают localStorage при инициализации стора или в теле компонента. На сервере это падение, а с ленивой инициализацией на клиенте разметка расходится с серверной, и React перерисовывает поддерево.