Как мне легче всего определить узкие места в производительности рендеринга React?

Aug 15 2020

У меня возникла проблема с определением узких мест в производительности рендеринга при работе со средством просмотра JSON. С небольшим количеством элементов он работает хорошо, но в определенный момент становится раздражающе медленным.

Проверяя профилировщик, кажется, что элементы отрисовываются достаточно быстро, но я заметил несколько проблем, которые я не знаю, как решить.

Обзор

  • Приложение представляет собой средство просмотра JSON, которое позволяет развернуть / минимизировать все элементы сразу, а также отдельные элементы.
  • Производительность нормальная с небольшим количеством элементов, но, похоже, резко падает с увеличением количества элементов.
  • При профилировании обоих моих методов фильтрации объектов, performance.now()а также при проверке времени рендеринга в React DevTools, цифры кажутся нормальными. Я мог неправильно это истолковать.
  • Я пробовал использовать React.memo()элементы без состояния (особенно ключ / значение, который является наиболее часто отображаемым компонентом), но, похоже, это не улучшает производительность заметно. По общему признанию, я не уверен, достаточно ли я понимаю причины мемоизации компонентов React, чтобы реализовать это с пользой.

Выполнение

  • В настоящее время мое приложение загружает данные в родительский объект, который передается в компонент, загружающий дерево JSON с использованием рекурсивного элемента.
  • Загрузка канала JSON из URL-адреса изменяет состояние родительского компонента, который фильтруется с помощью вспомогательного метода, который использует значения, введенные в поле ввода.

вопросы

Есть две функции, которые воспроизводят медленное время отклика с (небольшими) документами JSON:

  • Кнопка "Развернуть все"
  • Первые несколько нажатий клавиш в запросе фильтра

В текущей реализации как фильтрация, так и расширение все триггеры вызывают display: noneизменение дочерних элементов, и такое поведение заставляет меня думать, что я делаю что-то неэффективно для обработки этого варианта использования.

Шаги размножения

Код доступен здесь: https://codesandbox.io/s/react-json-view-4z348

С производственной сборкой здесь (не лучше): https://csb-4z348.vercel.app/

Чтобы воспроизвести проблему, поиграйте с функцией «Развернуть все» (знак «плюс» рядом с входом фильтра) и некоторыми входами фильтра.

Затем попробуйте загрузить фид JSON с дополнительными элементами (вы можете протестировать мой фид GitHub API ) и попробуйте отфильтровать / развернуть все. Обратите внимание на основной удар по производительности.

Что я заметил

  • При логировании useEffect сведение к минимуму вызывает примерно в 2 раза больше повторных рендеров, чем расширение всего.
  • По мере того, как входные данные фильтра становятся более конкретными, производительность (логически) улучшается, поскольку отображается меньше элементов.

Вопрос

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

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

Я ценю ваше время и заранее благодарю вас за любые советы, которые вы могли бы дать!

Ответы

2 HarrisonGrieve Aug 16 2020 at 15:50

Кажется, я ответил на свой вопрос. Проблема заключалась в проблеме согласования из-за использования UUID в качестве ключевой опоры в моих дочерних компонентах, что приводило к их повторной визуализации при каждом изменении состояния минимизации. Из документов:

Ключи должны быть стабильными, предсказуемыми и уникальными. Нестабильные ключи (например, созданные Math.random ()) вызовут ненужное воссоздание многих экземпляров компонентов и узлов DOM, что может вызвать снижение производительности и потерю состояния дочерних компонентов.

Я оставлю шаги здесь для всех, кто столкнется с этой проблемой.


После (слишком долгого) копания в профилировщике производительности я заметил, что каждый раз, когда я сворачивал или разворачивал элементы, каждый дочерний элемент монтировался снова. Посоветовавшись с Google по более конкретному запросу, я нашел это сообщение в блоге и понял, что совершаю эту вопиющую ошибку производительности.

Как только я нашел источник проблемы, я нашел много других ссылок на него.

После исправления ключевого свойства время взаимодействия уменьшилось примерно на 60% для свертывания / развертывания всего.

Наконец, я запомнил некоторые другие компоненты, связанные с мгновенным фильтром, и, наконец, он работает так хорошо, как мне хотелось бы.

Спасибо всем, кто взглянул на это тем временем, и я надеюсь, что это будет полезно для всех, кто может столкнуться с этим.