Варианты оптимизации кеширования в React

Варианты оптимизации кеширования в React

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

Хуки React для мемоизации

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

Чтобы минимизировать нагрузку на ЦП, избегая ненужных нагрузок, React предоставляет два хука, которые помогают в мемоизации. Хуки следуют процессу, в котором результаты кэшируются в памяти и возвращаются без повторных вычислений, когда мы имеем те же входные данные. В случае отличия данных, которые поступают на вход кеш становится недействительным.

useMemo()

useMemo() — это хук, предоставляемый React для мемоизации, который помогает сохранять кэшированные значения для одних и тех же предоставленных значений. Он отслеживает ввод и возвращает ранее выполненный результат.
Давайте посмотрим на пример. Предположим, что нам нужно добавить два огромных числа в компонент со следующей функцией:

Написанная выше функция сильно нагружает ЦП, и поэтому ее следует вычислять только при изменении значений a и b. Однако по умолчанию она будет запускаться при каждом повторном рендеринге.

С помощью useMemo() мы можем сохранить результат для определенных значений, то есть функция не будет вычислять, и мы получим ранее рассчитанный результат напрямую:

Значение хранится в memoizedValue. Мы передали массив зависимостей в useMemo, который сообщает ему, когда запускать расчет снова. В нашем случае он будет запущен при изменении любого из значений.

UseCallback()

С useCallback() мы также получаем возможность мемоизирования, но эта функция работает по-другому. useCallback() не запоминает значение, а вместо этого запоминает предоставленную ему функцию обратного вызова. Давайте рассмотрим небольшой пример:

При использовании useCallback() приведенная выше функция выглядит как код ниже:

useCallback() запомнит функцию увеличения, выполняющуюся только при изменении данной зависимости. Она не отслеживает ввод или значение, возвращаемое функцией.

Ленивая загрузка компонентов React

Ленивая загрузка (Lazy loading) в React отрисовывает необходимые компоненты заранее и откладывает загрузку несущественных компонентов на конец.

Этот подход настоятельно рекомендуется для повышения производительности, особенно в больших приложениях. В React есть встроенные опции для отложенной загрузки компонентов.

Мы создали компонент с именем Artists и хотим, чтобы он загружался с помощью lazy load. Можно сделать это следующим образом:

Сначала мы импортируем lazy из ‘react’ и используем его, как показано ниже:

useRef()

Мы знаем, что всякий раз, когда мы используем useState() в компоненте, он вызывает повторный рендеринг при изменении состояния. Чтобы отслеживать состояние без повторного рендеринга, React представил хук useRef().

Есть несколько сценариев, в которых useState() может оказаться неподходящим решением для вашего приложения. useRef() идеально подходит для ситуаций, когда нам нужно состояние, которое не вызывает повторного рендеринга и не влияет на видимую информацию, отображаемую компонентом. Например, вы можете использовать его для подсчета рендеров:

В приведенном выше коде у нас есть простой переключатель, который повторно отображает компонент. counter — это изменяемая ссылка, сохраняющая свое значение. Мы можем сделать то же самое с useState(), но это вызовет два рендера для каждого переключения.

Кэшированные селекторы Redux

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

В React Redux есть хук useSelector(), который используется для получения состояния из хранилища. Проблема useSelector() заключается в том, что он запускается каждый раз при рендеринге компонента. useSelector() может быть идеальным в некоторых случаях, но не всегда. В большинстве случаев — данные, возвращаемые селекторами, не меняются, что делает вычисления ненужными. Давайте рассмотрим пример:

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

Чтобы решить проблему, мы кэшируем результаты функции селектора. Несмотря на то, что для этого нет встроенных решений React, у нас есть много сторонних библиотек, которые позволяют нам создавать кешированные селекторы. Давайте воспользуемся Reselect, известным решением для кеширования селекторов.

Reselect

Reselect- популярная библиотека для создания мемоизированных селекторов. Вы можете установить ее в свой проект с помощью следующей команды:

Мы можем использовать Reselect следующим образом:

В приведенном выше коде мы импортировали createSelector из Reselect, который принимает селектор и возвращает его мемоизированную версию. В мемоизированной версии компонент не будет вычислять значение селекторов даже после тысяч повторных отрисовок, если не изменится значение postReducer. CreateSelector оказался отличным решением для решения проблем с производительностью в более крупных приложениях.

Оптимизация вызовов API с помощью React Query

React по-своему обрабатывает асинхронные операции, что иногда является проблемой для разработчиков. Обычным шаблоном для асинхронных операций является выборка данных сервера в useEffect Hook, которая запускается при каждом рендеринге и каждый раз извлекает новые данные, даже если на сервере нет изменений.

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

Фрагменты React

Если вы разработчик React, вы, вероятно, сталкивались с ошибкой, которая требует обернуть компонент родительским div. Если дополнительный div в вашем компоненте не нужен, нет смысла его добавлять. Например, если у вас есть тысяча компонентов в приложении React, у вас будет тысяча дополнительных div, которые могут быть тяжелыми для DOM. Чтобы этого избежать, React дает вам возможность использовать фрагменты:

Приведенный ниже фрагмент кода точно такой же, как и код выше, с использованием <> в качестве ярлыка для React.Fragment:

При любом подходе вы избегаете добавления лишнего div, что приводит к уменьшению разметки DOM, повышению производительности рендеринга и сокращению накладных расходов на память.

Виртуальные списки React

Часто нам нужно отображать большие списки в браузере; это требует больших затрат ресурсов браузера, потому что он должен создавать новые узлы и рисовать их все на экране.

Чтобы сделать этот процесс эффективным, у нас есть возможность использовать виртуальные списки. Виртуальный список отображает только несколько элементов по мере необходимости, просто заменяя их, когда пользователь динамически прокручивает элементы.

Визуализация выполняется быстрее, чем изменение модели DOM, поэтому вы можете быстро отображать тысячи элементов списка с помощью виртуального списка. React-virtualized — отличная библиотека, которая содержит компоненты для визуализации виртуальных списков.

Функциональные компоненты

React начинался с использования базовых компонентов класса, однако теперь рекомендуется использовать функциональные компоненты из-за их легкости. Функциональные компоненты — это в основном функции, которые создавать намного быстрее, и их легче минимизировать, уменьшая размер пакета.

Заключение

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

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

Автор: Kasra

Источник: javascript.plainenglish.io

Редакция: Команда webformyself.

Читайте нас в Telegram, VK, Яндекс.Дзен

Метки:

Похожие статьи:

Комментарии Вконтакте:

Комментарии запрещены.