Какие есть способы оптимизации рендеринга в react?
Это процесс снижения количества лишних перерисовок компонентов, что улучшает производительность приложения. React повторно рендерит компоненты, когда их состояние (
state) или свойства (
props) изменяются. Однако часто это приводит к ненужным рендерам, которые можно избежать.
ПроизводительностьЧем больше компонентов рендерится без необходимости, тем больше времени тратится на вычисления и обновления DOM.
Экономия ресурсовИзбегая лишних рендеров, приложение работает быстрее, а пользовательский интерфейс становится более отзывчивым.
Лучший UXПлавная работа интерфейса критична для сложных приложений с большим количеством данных.
Мемоизация компонентовReact предоставляет утилиту
React.memo, чтобы предотвращать ререндеринг компонента, если его
props не изменились.
import React from 'react';
const MyComponent = React.memo(({ count }) => {
console.log('Рендер компонента');
return <div>Счётчик: {count}</div>;
});
// Использование
export default function App() {
const [count, setCount] = React.useState(0);
return (
<div>
<MyComponent count={count} />
<button onClick={() => setCount(count + 1)}>Увеличить</button>
</div>
);
}
Использование `useMemo` и `useCallback`Эти хуки используются для предотвращения повторных вычислений и создания функций при каждом рендере.
import React, { useMemo } from 'react';
function ExpensiveCalculationComponent({ number }) {
const calculatedValue = useMemo(() => {
console.log('Выполняются сложные вычисления...');
return number ** 2;
}, [number]); // Пересчитывается только если `number` изменился
return <div>Результат: {calculatedValue}</div>;
}Пример
useCallbackimport React, { useCallback, useState } from 'react';
const Child = React.memo(({ onClick }) => {
console.log('Рендер дочернего компонента');
return <button onClick={onClick}>Кликни меня</button>;
});
function Parent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log('Кнопка нажата');
}, []); // Создаётся одна и та же функция между рендерами
return (
<div>
<Child onClick={handleClick} />
<button onClick={() => setCount(count + 1)}>Увеличить {count}</button>
</div>
);
}Разделение кода и ленивый рендерингИспользование
React.lazy и
Suspense позволяет загружать компоненты только тогда, когда они необходимы.
import React, { Suspense } from 'react';
const LazyComponent = React.lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Загрузка...</div>}>
<LazyComponent />
</Suspense>
);
}Проверка зависимости в `useEffect`Избегайте запуска побочных эффектов, если зависимости не изменились.
React.useEffect(() => {
console.log('Эффект сработал!');
}, [/* следите только за нужными зависимостями */]);Избегайте анонимных функций и объектов в `props`Передача новых объектов и функций через
props вызывает лишние рендеры.
<ChildComponent data={{ key: 'value' }} />Лучше так
const data = { key: 'value' };
<ChildComponent data={data} />;Разделение больших компонентовЕсли компонент слишком сложный, разделите его на более мелкие, чтобы React мог эффективно управлять состоянием и перерисовкой.
Использование ключей при рендере списковКаждый элемент списка должен иметь уникальный ключ, чтобы React мог правильно отслеживать изменения.
{items.map(item => (
<div key={item.id}>{item.name}</div>
))}👉
@frontendInterview