Как предотвратить ненужную повторную отрисовку компонента React
Понимание того, как React Native отображает компоненты, необходимо для создания эффективных и производительных приложений. Когда состояние или свойства компонента изменяются, React автоматически обновляет пользовательский интерфейс (UI), чтобы отразить эти изменения. В результате React снова вызывает метод отображения компонента, чтобы сгенерировать обновленное представление UI.
В этой статье мы рассмотрим три React Hooks и то, как они предотвращают ненужные рендеринги в React:
- useMemo
- userCallback
- userRef
Эти инструменты позволяют нам оптимизировать наш код, избегая ненужных повторных рендерингов, повышая производительность и эффективно сохраняя значения.
К концу этой статьи мы лучше поймем, как сделать наши приложения React более быстрыми и отзывчивыми, используя эти удобные хуки React.
Использование useMemo в React
В React useMemo
может предотвратить ненужные повторные рендеринги и оптимизировать производительность.
Давайте рассмотрим, как хук useMemo
может предотвратить ненужные повторные рендеринги в наших компонентах React.
Запоминая результат функции и отслеживая ее зависимости, useMemo
гарантирует, что процесс будет пересчитываться только при необходимости.
Рассмотрим следующий пример:
import { useMemo, useState } from 'react';
function Page() {
const [count, setCount] = useState(0);
const [items] = useState(generateItems(300));
const selectedItem = useMemo(() => items.find((item) => item.id === count), [
count,
items,
]);
function generateItems(count) {
const items = [];
for (let i = 0; i < count; i++) {
items.push({
id: i,
isSelected: i === count - 1,
});
}
return items;
}
return (
<div className="tutorial">
<h1>Count: {count}</h1>
<h1>Selected Item: {selectedItem?.id}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default Page;
Приведенный выше код представляет собой компонент React под названием Page
, который использует useMemo
для оптимизации вычисления selectedItem
.
Вот объяснение:
- Компонент поддерживает переменную состояния
count
c помощью хукаuseState
. - Состояние элементов инициализируется с помощью хука
useState
с результатом функцииgenerateItems
. selectedItem
вычисляется с помощьюuseMemo
, который запоминает результат операцииitems.find
. Он пересчитывается только при изменении количества или самих элементов.- Функция
generateItems
генерирует массив элементов на основе заданного количества. - Компонент отображает текущее
value
счетчика, идентификаторselectedItem
и кнопку для увеличения счетчика.
Использование useMemo
оптимизирует производительность, запоминая результат операции items.find
. Это гарантирует, что вычисление selectedItem
выполняется только при изменении зависимостей (количества или элементов), предотвращая ненужные повторные вычисления при последующих рендерингах.
Мемоизацию следует применять выборочно для операций с интенсивными вычислениями, поскольку она вносит дополнительные накладные расходы в процесс рендеринга.
Использование useCallback в React
Хук useCallback
в React позволяет мемоизировать функции, предотвращая их повторное создание во время каждого рендеринга компонента. Используя useCallback
, часть создается только один раз и повторно используется в последующих рендерах, пока ее зависимости остаются неизменными.
Рассмотрим следующий пример:
import React, { useState, useCallback, memo } from 'react';
const allColors = ['red', 'green', 'blue', 'yellow', 'orange'];
const shuffle = (array) => {
const shuffledArray = [...array];
for (let i = shuffledArray.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]];
}
return shuffledArray;
};
const Filter = memo(({ onChange }) => {
console.log('Filter rendered!');
return (
<input
type='text'
placeholder='Filter colors...'
onChange={(e) => onChange(e.target.value)}
/>
);
});
function Page() {
const [colors, setColors] = useState(allColors);
console.log(colors[0])
const handleFilter = useCallback((text) => {
const filteredColors = allColors.filter((color) =>
color.includes(text.toLowerCase())
);
setColors(filteredColors);
}, [colors]);
return (
<div className='tutorial'>
<div className='align-center mb-2 flex'>
<button onClick={() => setColors(shuffle(allColors))}>
Shuffle
</button>
<Filter onChange={handleFilter} />
</div>
<ul>
{colors.map((color) => (
<li key={color}>{color}</li>
))}
</ul>
</div>
);
}
export default Page;
Код выше демонстрирует простую цветовую фильтрацию и перемешивание в компоненте React. Давайте рассмотрим это шаг за шагом:
- Начальный массив цветов определяется как
allColors
. - Функция
shuffle
берет массив и перемешивает его элементы случайным образом. Для перемешивания она использует алгоритм Фишера-Йетса. - Компонент
Filter
— это мемоизированный функциональный компонент, который визуализирует элемент ввода. Он получает свойствоonChange
и запускает функцию обратного вызова при изменении входного значения. - Компонент
Page
является основным компонентом, который обеспечивает функциональность фильтрации и перемешивания цветов. - Переменные состояния
colors
инициализируются с помощью хукаuseState
, при этом начальное значение устанавливается какallColors
. Он представляет собой отфильтрованный список цветов. - Функция
handleFilter
создается с помощью хукаuseCallback
. Она принимает текстовый параметр и фильтрует массивallColors
на основе предоставленного текста. Затем отфильтрованные цвета устанавливаются с помощью функцииsetColors
из хукаuseState
. Массив зависимостей[colors]
гарантирует, что функцияhandleFilter
будет создана заново только в случае изменения состояния цветов, что оптимизирует производительность, предотвращая ненужные повторные рендеринги. - Внутри компонента
Page
есть кнопка для перемешивания цветов. При нажатии на кнопку вызывается функцияsetColors
с перемешанным массивомallColors
. - Компонент
Filter
визуализируется с помощью свойстваonChange
, установленного на функциюhandleFilter
. - Наконец, массив цветов сопоставляется для отображения списка цветовых элементов.
Хук useCallback
используется для запоминания функции handleFilter
, что означает, что функция создается только один раз и повторно используется при последующих рендерингах, если зависимости (в данном случае состояние цветов) остаются прежними.
Эта оптимизация предотвращает ненужные повторные рендеры дочерних компонентов, которые получают функцию handleFilter
как prop
, например, компонента Filter
.
Она гарантирует, что компонент Filter
не будет повторно рендериться, если состояние цветов не изменилось, что повышает производительность.
Использование useRef в React
Другой подход к повышению производительности в приложениях React и предотвращению ненужных повторных рендеров — использование хука useRef
. Используя useRef
, мы можем хранить изменяемое значение, которое сохраняется между рендерами, эффективно предотвращая ненужные повторные рендеры.
Эта техника позволяет нам поддерживать ссылку на значение без запуска обновлений компонентов при изменении этого значения. Используя изменчивость ссылки, мы можем оптимизировать производительность в определенных сценариях.
Рассмотрим следующий пример:
import React, { useRef, useState } from 'react';
function App() {
const [name, setName] = useState('');
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus();
}
return (
<div>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
ref={inputRef}
/>
<button onClick={handleClick}>Focus</button>
</div>
);
}
В примере выше есть простое поле ввода и кнопка. Хук useRef
создает ссылку с именем inputRef
. Как только нажимается кнопка, вызывается функция handleClick
, которая фокусируется на элементе ввода, обращаясь к текущему свойству inputRef
объекта ref
. Таким образом, это предотвращает ненужную повторную визуализацию компонента при изменении входного значения.
Чтобы обеспечить оптимальное использование useRef
, зарезервируйте его исключительно для изменяемых значений, которые не влияют на рендеринг компонента. Если изменяемое значение влияет на рендеринг компонента, его следует хранить в его состоянии.
Заключение
В этом руководстве мы изучили концепцию повторного рендеринга React и его потенциальное влияние на производительность наших приложений. Мы углубились в методы оптимизации, которые могут помочь смягчить ненужные повторные рендеры. React предлагает множество хуков, которые позволяют нам повысить производительность наших приложений. Мы можем эффективно хранить значения и функции между рендерами, используя эти хуки, значительно повышая производительность приложений React.