Условные хуки при рендеринге статического сайта - PullRequest
2 голосов
/ 05 марта 2019

Я использую response-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]
  )

Как правильно?

Ответы [ 2 ]

0 голосов
/ 05 марта 2019

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

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, что и было смыслом предупреждения.

0 голосов
/ 05 марта 2019

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

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

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

useEffect(() => { 
  window.requestAnimationFrame(() => {
      document.body.style.overflowY = loading ? 'hidden' : 'visible';
  });
}, [isLoading]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...