Как мне легче всего определить узкие места в производительности рендеринга React?
У меня возникла проблема с определением узких мест в производительности рендеринга при работе со средством просмотра 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 раза больше повторных рендеров, чем расширение всего.
- По мере того, как входные данные фильтра становятся более конкретными, производительность (логически) улучшается, поскольку отображается меньше элементов.
Вопрос
Хотя я был бы признателен за подталкивание в правильном направлении для этого конкретного случая, мне больше всего любопытно, как лучше всего определить, что вызывает эти проблемы с производительностью.
Я изучал возможность оконного вывода вывода, но это не мой первый выбор, и я почти уверен, что делаю что-то не так, а не потому, что слишком много элементов отображается.
Я ценю ваше время и заранее благодарю вас за любые советы, которые вы могли бы дать!
Ответы
Кажется, я ответил на свой вопрос. Проблема заключалась в проблеме согласования из-за использования UUID в качестве ключевой опоры в моих дочерних компонентах, что приводило к их повторной визуализации при каждом изменении состояния минимизации. Из документов:
Ключи должны быть стабильными, предсказуемыми и уникальными. Нестабильные ключи (например, созданные Math.random ()) вызовут ненужное воссоздание многих экземпляров компонентов и узлов DOM, что может вызвать снижение производительности и потерю состояния дочерних компонентов.
Я оставлю шаги здесь для всех, кто столкнется с этой проблемой.
После (слишком долгого) копания в профилировщике производительности я заметил, что каждый раз, когда я сворачивал или разворачивал элементы, каждый дочерний элемент монтировался снова. Посоветовавшись с Google по более конкретному запросу, я нашел это сообщение в блоге и понял, что совершаю эту вопиющую ошибку производительности.
Как только я нашел источник проблемы, я нашел много других ссылок на него.
После исправления ключевого свойства время взаимодействия уменьшилось примерно на 60% для свертывания / развертывания всего.
Наконец, я запомнил некоторые другие компоненты, связанные с мгновенным фильтром, и, наконец, он работает так хорошо, как мне хотелось бы.
Спасибо всем, кто взглянул на это тем временем, и я надеюсь, что это будет полезно для всех, кто может столкнуться с этим.