Если вы человек, который пишет код и создает потрясающие вещи с множеством обновлений пользовательского интерфейса в реальном времени, включая анимацию, управление жестами, придавая вашему пользовательскому интерфейсу невероятный вид, как в фильмах Disney / Pixar, то я должен сказать, что вы прошли через настоящую боль, будучи разработчиком, который может творить всю эту магию. Очевидно, когда я говорю «магия», это действительно похоже на удар волшебной палочки. Если бы это было так, насколько легко это было бы правильно? Но это не так. Вы создаете магию, а не просто используете ее. Подождите минуту!!! Теперь вы, ребята, можете задаться вопросом, почему я читаю лекцию о диснеевских вещах, рассказывая историю под названием «Воспоминание». Я знаю, что начал немного не с трека, но, ребята, поверьте мне, я хотел, чтобы вы все поняли, что делаете отличную работу. Вы заслуживаете похлопывания по себе. Сделайте это прямо СЕЙЧАС !! Непросто глубоко понять концепции и реализовать их с минимумом недостатков. Я рассказал обо всем, что не имеет отношения к вышеупомянутому, чтобы сказать вам об одном моменте, на котором вы, ребята, в настоящее время сосредоточены: производительность вашего приложения или его оптимизация. Вы здесь, потому что придаете одинаковое значение производительности своего приложения и его функциям. Хорошо, без дальнейших прощаний, давайте перейдем к нашей теме !!

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

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

Есть несколько терминов, которые вы должны понять, прежде чем начинать использовать запоминание в своем приложении. Они перечислены ниже. Если вы уже знаете их, можете перейти к следующей части.

  1. PureComponent: - Чистые компоненты в React основаны на чистых функциях JavaScript. Чистые функции - это не что иное, как функции, которые возвращают одинаковый вывод для определенных входных параметров. Кроме того, выходные данные не должны иметь зависимости вне функциональной области. Чистые компоненты в React не будут повторно отрисовываться, если состояние и свойства обновляются с одинаковыми значениями. shouldComponentUpdate () неявно реализован в классе PureComponent в React. Здесь проводится поверхностное сравнение состояния и свойств. Если предыдущее состояние и данные реквизита совпадают со следующими реквизитами или состоянием, компонент не подвергается повторной визуализации. React.PureComponent доступен только для компонентов класса. Таким образом, поскольку он ограничивает рендеринг, он обеспечивает более высокую производительность для компонента. Прочтите статью ниже, чтобы узнать больше о PureComponent. Https://reactjs.org/docs/react-api.html#reactpurecomponent
  2. Неглубокое сравнение: - В режиме неглубокого сравнения свойства объектов сравниваются с использованием === или строгого равенства и не будут проводить более глубокое сравнение свойств. При поверхностном сравнении примитивных значений (чисел, строк) он сравнивает их значения. При сравнении объектов он не сравнивает их атрибуты - сравниваются только их ссылки. Поэтому, если вы неглубоко сравните глубоко вложенный объект, он просто проверит ссылку, а не значения внутри этого объекта. Это может создать ложноотрицательные результаты при сравнении вложенных объектов. Https://reactjs.org/docs/shallow-compare.html
  3. Рендеринг: - Рендеринг происходит в React всякий раз, когда состояние компонента обновляется. Рендеринг - это процесс, в котором React будет собирать всю информацию, включая текущее состояние, свойства и желаемые изменения в пользовательском интерфейсе. Он вызовет функциональный компонент, и если это компонент класса, он вызовет метод render (). Виртуальный DOM в этом процессе еще не изменился. Как правило, может возникнуть неправильное понимание того, что рендеринг - это процесс синхронизации изменений в DOM. Но это не так.
  4. Согласование: - Виртуальная модель DOM (VDOM) - это концепция программирования, в которой идеальное или «виртуальное» представление пользовательского интерфейса хранится в памяти и синхронизируется с «реальной» DOM библиотекой, такой как ReactDOM. Этот процесс называется примирением. Это процесс расчета и сравнения изменений, которые необходимо применить к виртуальной DOM.
  5. Манипуляции с DOM: - После того, как React завершит вычисления, необходимые для применения в дереве приложения, с помощью встроенного пакета react будет применять все необходимые изменения в DOM. Они изменения применяются синхронно, и DOM обновляется. Это называется манипуляцией с DOM. Это происходит на этапе фиксации.
  6. Повторный рендеринг: - после первого рендеринга, второй или последующий рендеринг для обновления состояния обычно называется повторным рендерингом. Повторный рендеринг может быть вызван любым из следующих трех обстоятельств: когда свойство в компоненте обновляется, когда обновляется состояние в компоненте и когда вызывается метод рендеринга родительского компонента.

«Когда вы используете React, в определенный момент времени вы можете думать о функции render () как о создании дерева элементов React. При следующем обновлении состояния или свойств эта функция render () вернет другое дерево элементов React. Затем React необходимо выяснить, как эффективно обновить пользовательский интерфейс, чтобы он соответствовал самому последнему дереву ».

Теперь мы знакомы со всеми терминами, связанными с мемоизацией. Это вызвало небольшое отклонение от нашей основной темы, но поверьте мне, ребята, понимание этих концепций очень важно при разработке приложения.

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

  1. React.memo (): - React.memo - это компонент более высокого порядка, который оптимизирует производительность функциональных компонентов. Его функциональность аналогична React.PureComponent, но предназначена для функциональных компонентов. То есть, если функциональный компонент снабжен одними и теми же реквизитами и если его вывод, который он отображает, тот же, то мы можем каждый раз пропускать повторный рендеринг этого компонента. Об этом позаботится React.memo (). Это помогает в быстром рендеринге, запоминая результат. React пропустит процесс рендеринга для компонента и не выполнит вычисление разницы виртуальных DOM, он просто повторно использует последний результат рендеринга. Как было сказано в начале, React.memo () выполняет поверхностное сравнение, например PureComponent. Итак, если наш компонент имеет какую-либо вложенную структуру данных в качестве опоры, нам нужно будет написать нашу собственную функцию сравнения и передать ее в React.memo ().
  2. Перехватчик useCallback: - Этот перехватчик также используется для предотвращения нежелательного повторного рендеринга в нашем коде и, таким образом, делает его более быстрым и эффективным. Иногда нам может потребоваться комбинация React.memo и useCallback. Как я уже упоминал ранее, React.memo использует неглубокое сравнение, чтобы найти разницу между предыдущей опорой и следующей опорой. Это отлично работает для примитивных типов. Но если функциональный компонент имеет массив, объект или даже функцию обратного вызова в качестве опоры, то поверхностное сравнение дает ложноотрицательные результаты. Таким образом, при повторном рендеринге родительского компонента каждый раз создаются новые функции обратного вызова, даже если мы заключили наш компонент в React.memo. Здесь на помощь приходят хуки useCallback. Мы должны обернуть нашу функцию обратного вызова с помощью useCallback и передать зависимости. Поэтому всякий раз, когда происходит вызов функции, хуки useCallback возвращают запомненную функцию. Он создаст новую функцию, только если зависимости изменятся.
  3. Хук useMemo: похож на хук useCallback. Но вместо того, чтобы запоминать обратный вызов, он запоминает любой тип значения. Мы также должны передать список зависимостей в useMemo. Поэтому всякий раз, когда зависимости изменяются, он снова вызывает функцию, выполняет пересчет и запоминает новое значение.

Хорошо, теперь мы говорили слишком много теории. Давайте посмотрим на код и поймем, как использовать каждую из ловушек для оптимизации нашего кода.

Случай: - 1 - Без мемоизации

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

Теперь ниже, если вы проверите консоль, вы увидите, что дочерний элемент также получает повторный рендеринг для каждого щелчка в родительском элементе. Но почему? Это лишнее право. Потому что для дочернего компонента нет обновления пользовательского интерфейса. Тогда нет смысла его рендерить заново. К сожалению, это поведение React по умолчанию. Все компоненты в родительском дереве будут повторно визуализированы, если в родительском дереве есть обновление состояния.

Случай: - 2 - С React.memo

Теперь обернем ChildItem с помощью React.memo () и посмотрим, что произойдет. Как обсуждалось ранее, это вызовет неглубокое сравнение текущего и предыдущего реквизита. Если какое-либо свойство будет изменено, то повторно отобразится только ChildItem.

Теперь вы видите волшебство. Только родительский объект подвергается повторному рендерингу.

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

Случай: -3 - с функцией обратного вызова в качестве опоры

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

Выше приведены журналы, когда мы нажимаем только кнопку в родительском компоненте. Если вы видите журналы, вы можете видеть, что childItem снова перерисовывается, хотя мы обернули его с помощью React.memo (). Это связано с тем, что поверхностное сравнение вернет false для текущего и предыдущего реквизита, так как у нас в качестве пропса непримитивное значение. В следующем случае мы увидим, как это исправить.

Случай: - 4 - С обработчиком useCallback ()

Чтобы решить указанную выше проблему, как обсуждалось ранее, мы заключим нашу функцию обратного вызова в useCallback. Таким образом, useCallback будет кэшировать функцию и создавать только новую функцию при изменении ее зависимости.

Теперь, если вы видите журналы нажатия родительской кнопки, он будет повторно отображать только родительский компонент.

Случай: -5 - с обработчиком useMemo ()

Как обсуждалось ранее, разница между useMemo и useCallback заключается в том, что useMemo запоминает результат функции, а не саму функцию.

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

В приведенном ниже коде показано использование ловушки useMemo для того же ввода для вызова функции. В журналах можно увидеть, что функция вызывается только один раз. Да!! Мы добились оптимизации.

Вы можете найти весь исходный код в репозитории git ниже.



Уфф… !! Это было очень важно. Но это нормально. Вы узнали очень важную концепцию разработки приложений React Native. Обязательно соблюдайте это при написании следующего функционального компонента, если это необходимо.

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

На этом пока все. Если вам понравилась эта статья, осыпьте меня хлопками, так что это будет для меня огромной мотивацией к написанию следующих статей, а также пусть это дойдет до нуждающихся. Также "Follow Me" для получения обновлений статей.

Оставайтесь в безопасности ... Оставайтесь голодными .. !!