Реагировать на хуки: ленивая загрузка останавливается useLayoutEffect?

В моем веб-приложении есть верхняя панель навигации, высота которой может изменяться. Он закреплен в верхней части экрана, css position: fixed. Чтобы переместить содержимое страницы под ним, у меня есть разделитель div, который обновляет свою высоту, чтобы соответствовать высоте заголовка, и подталкивает все остальное вниз.

Я обновляю свое приложение, чтобы использовать перехватчики React. У меня есть крючок useLayoutEffect, который проверяет высоту панели навигации и обновляет высоту прокладки, чтобы она соответствовала. Согласно документации React:

В отличие от componentDidMount или componentDidUpdate эффекты, запланированные с помощью useEffect, не блокируют обновление экрана браузером. Это делает ваше приложение более отзывчивым. Большинство эффектов не обязательно должно происходить синхронно. В редких случаях, когда они это делают (например, при измерении макета), существует отдельный хук useLayoutEffect с API, идентичным useEffect.

Кажется, я обнаружил, что ленивая загрузка React прерывается useLayoutEffect. Вот CodeSandBox:

https://codesandbox.io/s/5kqxynp564

За навигационной панелью скрыт блок div, содержащий текст «ЕСЛИ ВЫ УВИДИТЕ, ЧТО ЭТО ИСПОЛЬЗОВАНИЕ РАБОТАЕТ». При использовании прямого импорта размер блока div над этим текстом устанавливается в соответствии с размером панели навигации, при этом текст перемещается вниз под панелью навигации, и текст становится видимым. Когда используется React.lazy, useLayoutEffect (в AppBarHeader.js) не работает.

Ленивая загрузка происходит в App.js:

//LOADING <COUNTER/> THIS WAY WORKS
// import Counter from "./Counter";

//LAZY LOADING <COUNTER/> THIS WAY BREAKS useLayoutEffect
const CounterPromise = import("./Counter");
const Counter = React.lazy(() => CounterPromise);

Что я скучаю?


person VikR    schedule 16.02.2019    source источник
comment
Не могли бы вы выложить здесь минимальную репродукцию?   -  person ᆼᆺᆼ    schedule 16.02.2019
comment
Когда вы видите ошибку, сообщите об этом в репозиторий React.   -  person Dan Abramov    schedule 16.02.2019
comment
@DanAbramov Я создал для этого проблему. Ссылка на это есть в моем ответе.   -  person Ryan Cogswell    schedule 16.02.2019
comment
@DanAbramov Подойдет.   -  person VikR    schedule 17.02.2019


Ответы (1)


Похоже, что это реальная ошибка во времени выполнения useLayoutEffect для компонента в Suspense, где какой-то другой компонент загружается лениво. Если AppBarHeader загружается лениво, а Counter - нет, он работает нормально, но при Counter ленивой загрузке useLayoutEffect AppBarHeader выполняется до того, как он полностью отобразится в DOM (высота по-прежнему равна нулю).

Эта песочница «исправляет» это очень хакерским способом, который помогает дополнительно продемонстрировать, что происходит.

Я добавил в App.js следующее:

  replaceRefHeader = () => {
    this.setState({ ref_header: React.createRef() });
  };

а затем передал это Counter:

<Counter replaceRefHeader={this.replaceRefHeader} history={routeProps.history} />

Затем в Counter:

const Counter = ({ replaceRefHeader }) => {
  useLayoutEffect(() => {
    replaceRefHeader();
  }, []);

а затем я помещаю [props.ref_header] в массив зависимостей AppBarHeader useLayoutEffect.

Я не предлагаю вам сделать это именно так (хотя что-то подобное может сработать как временное решение). Это было просто, чтобы более четко продемонстрировать проблему времени.

Я зарегистрировал здесь новую проблему: https://github.com/facebook/react/issues/14869

person Ryan Cogswell    schedule 16.02.2019