TransWikia.com

Элемент имеет нулевые размеры при вызове offsetWidth offsetHeight в componenDidMount React

Stack Overflow на русском Asked by Alexandr Antonenko on August 30, 2021

Необходимо в жизненном цикле ComponentDidMount компонента получить размеры элемента, для этого в методе render() я повесил ссылку на элемент:

public render() {
return (
  <div ref={this.gridRef} id="grid-widget" className="h-100 overflow-hidden w-100 p-0 d-flex flex-column">
    {this.renderGrid()}
  </div>
);
}

В ComponentDidMount получаю элемент и беру его размеры:

public componentDidMount() {
     this.props.recalculateGrid({ 
         width: this.gridRef.current.offsetWidth, 
         height: this.gridRef.current.offsetHeight 
     });
}

Но дело в том, что в данный момент размеры элемента w = 0 и h = 0. Хотя если открыть разметку, то элемент имеет размеры.
Причем до определенного момента это работало, после изменения стилей это сломалось, к сожалению, конкретное изменение сложно найти, но хотелось бы понять, почему так вообще происходит.
Можно ли повесить на элемент какой то коллбэк, который сработает тогда, когда у элемента будут размеры?

3 Answers

Я решил свою проблему. Пробовал useEffect это не помогло. Пробовал использовать setTimeout, иногда помогает, иногда вываливаются ошибки связанные с рекурсией. Пробовал MutationObserver, но, к сожалению, он не реагирует на изменение размеров блока.

Мне пришлось откатывать коммиты и смотреть когда этот баг пропадет. Хочу обратить внимание, что баг воспроизводится не с первого раза, иногда нужно несколько раз перезагрузить страницу.

Компонент Grid, с которым у меня была проблема лежит в контейнере. Помимо него в этом контейнере есть еще два компонента. Все три компонента я импортировал в контейнер с помощью lazy import. Я переписал это на обычные импорты.

Сам компонент контейнера вместе с другими компонентами (достаточно простыми) так же импортировался с помощью lazy import. Импорт контейнера я оставил на lazy, а вот у компонентов, которые импортировались рядом с этим контейнером я убрал lazy импорт и это помогло.

Но таким решением я не очень доволен, оно не чувствуется надежным. Так что я продолжаю поиски более надежного метода.

Answered by Alexandr Antonenko on August 30, 2021

React никак не отвечает за отрисовку стилей. цикл componentDidMount сработает тогда, когда у компонента будут смонтирована разметка и его логика. за отрисовку и перерисовку отвечают графические движки (например, WebKit) и сам JS движок (его EventLoop). это процесс банально называется repaint/redraw.

в результате, теоретически, EventLoop первоначально отрисовывает Ваш компонент, ставит в очередь componentDidMount и только после этого делает redraw Вашего документа

Answered by Август on August 30, 2021

Дело явно в стилях или в том, что соседние компоненты делают что-то асинхронно. Для того, чтобы сказать, что конкретно не так, в вопросе кода недостаточно. Обрати внимание, что хотя componentDidMount вызывается когда текущий элемент примонтирован, может оказаться, что последующие элементы (sibling) ещё нет (у меня с ангуляром была такая проблема).

Что касается второй части вопроса - можно ли отследить изменение размеров dom-элемента: в современных браузерах имеется ResizeObserver, который предназначен именно для этого. Но это не означает, что стоит его бросаться использовать - вполне допускаю, что есть более хорошее решение, задействующее только css.

Answered by Qwertiy on August 30, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP