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. Продолжайте учиться и экспериментировать.

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Dr. Derek Austin: 7 React Performance Optimization Techniques You Can’t Ignore

Предыдущая статьяЛучшие практики разработки на Python
Следующая статьяКак использовать управляемые Gradle устройства с собственными девайсами