1. Использование React.memo (HOC, а не хук)
import React, { memo } from 'react'
interface Props {
title: string
subtitle: string
}
const MyComponent: React.FC<Props> = memo(({ title, subtitle }) => {
return (
<div>
<h1>{title}</h1>
<h2>{subtitle}</h2>
</div>
)
})
React.memo
— это компонент высшего порядка (HOC), который можно использовать для предотвращения ненужных повторных рендерингов функциональных компонентов.
Обернув компонент в React.memo
, вы обеспечите его повторный рендеринг только при изменении его пропсов. Это особенно полезно при работе со сложными компонентами, которые требуют больших затрат на рендеринг.
2. Оптимизация обработчиков событий с помощью useCallback
import React, { useState, useCallback } from 'react'
const Counter: React.FC = () => {
const [count, setCount] = useState(0) const increment = useCallback(() => {
setCount(prevCount => prevCount + 1)
}, [])
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
)
}
Используя хук useCallback
, можно мемоизировать обработчики событий, обеспечивая таким образом их изменение только при изменении зависимостей, указанных в массиве зависимостей. Это предотвращает ненужные повторные рендеринги дочерних компонентов, которые зависят от мемоизированных обработчиков событий.
3. Виртуализация длинных списков с помощью react-window
import React from 'react'
import { FixedSizeList as List } from 'react-window'
const Row: React.FC<{ index: number; style: React.CSSProperties }> = ({
index,
style,
}) => {
return (
<div style={style}>
<p>{`Row ${index}`}</p>
</div>
)
}
const VirtualizedList: React.FC = () => {
const itemCount = 1000
return (
<List height={500} itemCount={itemCount} itemSize={50} width={300}>
{Row}
</List>
)
}
Важно оптимизировать производительность рендеринга длинных списков и таблиц. С помощью react-window
можно эффективно отрендерить большой список, и при этом будут отображаться только видимые элементы, а количество создаваемых и обновляемых элементов DOM сократится. Эта техника, известная как “оконное управление” (“windowing”) или “виртуализация”, способна значительно повысить производительность.
4. Ленивая загрузка компонентов с помощью React.lazy и Suspense
import React, { lazy, Suspense } from 'react'
const LazyLoadedComponent = lazy(() => import('./LazyLoadedComponent'))
const App: React.FC = () => {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<LazyLoadedComponent />
</Suspense>
</div>
)
}
Ленивая загрузка — это техника оптимизации, которая откладывает загрузку некритичных компонентов до тех пор, пока они не понадобятся. С помощью React.lazy
и Suspense
можно легко реализовать ленивую загрузку для компонентов. Это позволит значительно улучшить время начальной загрузки приложения за счет уменьшения количества JavaScript, который необходимо загрузить и распарсить.
5. Использование API React.Profiler для выявления узких мест производительности
import React, { Profiler } from 'react'
const onRender = (
id: string,
phase: 'mount' | 'update',
actualDuration: number,
baseDuration: number,
startTime: number,
commitTime: number,
interactions: Set<{ id: number; name: string; timestamp: number }>
) => {
console.log('Profiler:', {
id,
phase,
actualDuration,
baseDuration,
startTime,
commitTime,
interactions,
})
}
const App: React.FC = () => {
return (
<Profiler id="MyComponent" onRender={onRender}>
<MyComponent />
</Profiler>
)
}
API для работы сReact.Profiler
позволяет измерять производительность компонентов путем сбора информации о тайминге по каждой фазе рендеринга.
Используя компонент Profiler
, можно определить узкие места в производительности и соответствующим образом оптимизировать приложение.
6. Оптимизация обновления состояний с помощью Immer
import React, { useState } from 'react'
import produce from 'immer'
interface User {
id: number
name: string
}
const App: React.FC = () => {
const [users, setUsers] = useState<User[]>([
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
])
const updateUser = (id: number, newName: string) => {
setUsers(
produce((draftUsers: User[]) => {
const user = draftUsers.find(user => user.id === id)
if (user) {
user.name = newName
}
})
)
}
return (
// ...
)
}
Immer — это популярная библиотека, которая упрощает работу с неизменяемыми структурами данных в JavaScript. С помощью функции produce
в Immer можно написать читаемую логику обновления состояния и гарантировать, что состояние останется неизменным. Это также предотвратит непредвиденные побочные эффекты и повысит производительность.
7. Использование троттлинга и дебаунсинга для обработчиков ввода
import React, { useState, useCallback } from 'react'
import { debounce } from 'lodash-es'
const SearchBox: React.FC = () => {
const [searchTerm, setSearchTerm] = useState('')
const handleSearch = useCallback(
debounce((value: string) => {
setSearchTerm(value)
}, 300),
[]
)
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
handleSearch(event.target.value)
}
return (
<div>
<input type="text" onChange={handleChange} />
</div>
)
}
Троттлинг и дебаунсинг — методы, используемые для ограничения скорости выполнения функции. Это родственные, но разные понятия в контексте компьютерных наук.
Троттлинг — это прямое уменьшение скорости срабатывания. Дебаунсинг — техника поддержания частоты срабатывания ровно на 0 до периода покоя, а затем срабатывания слушателя ровно один раз.
Применяя эти техники к обработчикам ввода, можно сократить количество вызовов функций и повысить производительность, особенно при решении таких задач, как получение данных из API и фильтрация большого набора данных.
В примере выше используется debounce
из lodash-es
, популярной библиотеки lodash
, экспортируемой в виде ES-модулей для встряски дерева вызовов. Debounce ограничит скорость вызова функции handleSearch
.
Заключение
Мы рассмотрели 7 методов оптимизации производительности для приложений React. Применение этих стратегий обеспечит безотказную и эффективную работу приложения, а значит — и превосходный пользовательский опыт. Помните, что производительность — это постоянная проблема, требующая непрерывного мониторинга и оптимизации приложения.
Конечно, вы можете применять и другие стратегии оптимизации производительности. Однако эти 7 методов станут для вас прочным фундаментом при создании высокопроизводительных приложений React. Продолжайте учиться и экспериментировать.
Читайте также:
- Обрабатываем ошибки в React: полное руководство
- Совместное использование компонентов React с Webpack 5
- Как создать приложение Todo на React
Читайте нас в Telegram, VK и Дзен
Перевод статьи Dr. Derek Austin: 7 React Performance Optimization Techniques You Can’t Ignore