Условные хуки при рендеринге статического сайта

Я использую react-static для создания статического веб-сайта. Используя useLayoutEffect из новый хук API, я получаю это предупреждение на этапе статического рендеринга (тот же API, что и рендеринг на стороне сервера):

Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format.
  This will lead to a mismatch between the initial, non-hydrated UI and th  e intended UI.
  To avoid this, useLayoutEffect should only be used in components that render exclusively on the client.

Конечно, это имеет смысл. Но как избавиться от этого предупреждения, если вы уверены, что не будет никакого несоответствия?

В моем эффекте макета я лишь добавляю немного CSS к тегу body, поэтому не будет никаких несоответствий на этапе гидратации на клиенте (поскольку body не является делом React).

React строго запрещает использование условных хуков, но в этом конкретном случае очень не имеет смысла сделать что-то вроде:

if (typeof window !== 'undefined')
  useLayoutEffect(() => {
      document.body.style.overflowY = loading ? 'hidden' : 'visible'
    },
    [loading]
  )

Каков правильный путь?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
2
0
1 611
2

Ответы 2

Я думаю, что вы должны использовать контекст для передачи значения «скрытый/видимый» другим компонентам. В данном случае компонент, который отображает оболочку всей страницы.

useEffect(() => { 
  fnSetContextValue(isLoading ? 'hidden' : 'visible') 
}, [isLoading]);

Вы также можете попробовать использовать функцию запросAnimationFrame вместо контекста:

useEffect(() => { 
  window.requestAnimationFrame(() => {
      document.body.style.overflowY = loading ? 'hidden' : 'visible';
  });
}, [isLoading]);

Использование useEffect вместо useLayoutEffect действительно не вызывает предупреждение, но тогда я теряю синхронный аспект useLayoutEffect.

ostrebler 05.03.2019 11:43

О, я написал useEffect в своем посте, правда. Исправленный. Я имел в виду useLayoutEffect.

ostrebler 05.03.2019 11:58

Итак, вот решение не очень грязный, которое я придумал. Вместо реализации наивного решения, т.е. условный хук:

const Layout = () => {
  const [loading, setLoading] = useState()

  if (typeof window !== 'undefined')
    useLayoutEffect(() => {
      document.body.style.overflowY = loading ? 'hidden' : 'visible'
    }, [loading])

  return ( ... )
}

export default Layout

который кажется грязным, антишаблонным, семантически неверным и во многих случаях бесполезным (зачем проверять window при каждом рендеринге?), я просто помещаю условие вне компонента:

const LayoutView = ({ loading, setLoading }) => ( ... )

const Layout = (typeof window === 'undefined') ? (
  () => {
    const [loading, setLoading] = useState()
    return <LayoutView loading = {loading} setLoading = {setLoading}/>
  }
): (
  () => {
    const [loading, setLoading] = useState()
    useLayoutEffect(() => {
      document.body.style.overflowY = loading ? 'hidden' : 'visible'
    }, [loading])
    return <LayoutView loading = {loading} setLoading = {setLoading}/>
  }
)

export default Layout

Однако будьте осторожны, это работает только потому, что мой эффект макета не влияет на часть React DOM, в чем и был весь смысл предупреждения.

Другие вопросы по теме