← Назад к вопросам

Какие знаешь способы оптимизации ререндера?

2.0 Middle🔥 241 комментариев
#React#Оптимизация и производительность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Оптимизация ререндера в React

Реrendер происходит когда меняется state или props компонента. Чем больше компонентов ререндерится, тем медленнее приложение. Существует несколько проверенных способов оптимизации.

1. React.memo

Предотвращает ререндер если props не изменились:

const UserCard = React.memo(({ user, onClick }) => {
  console.log("render");
  return <div onClick={onClick}>{user.name}</div>;
});

// Ререндер только если user или onClick изменились

Важно: функции в props всегда новые, поэтому нужен useCallback

const Parent = () => {
  const handleClick = useCallback(() => {
    // логика
  }, []); // dependencies
  
  return <UserCard onClick={handleClick} />;
};

2. useMemo

Мемоизирует дорогие вычисления:

const expensiveList = useMemo(() => {
  return users.filter(u => u.active).map(u => u.name);
}, [users]); // пересчитается только если users изменился

return <List items={expensiveList} />;

Когда использовать:

  • Сложные вычисления (фильтрация, сортировка, трансформация больших массивов)
  • Значение передаётся как props в React.memo компонент

3. useCallback

Мемоизирует функции для передачи как props:

const handleDelete = useCallback((id) => {
  setUsers(prev => prev.filter(u => u.id !== id));
}, []); // зависимостей нет

// handleDelete всегда одна и та же функция
return <UserList onDelete={handleDelete} />;

4. Правильная структура state

Если state разбит на части, ререндер затрагивает только нужные компоненты:

// Плохо - любое изменение ререндерит всё
const [data, setData] = useState({ user, products, ui });

// Хорошо - разделяем state
const [user, setUser] = useState(null);
const [products, setProducts] = useState([]);
const [ui, setUI] = useState({});

5. Контекст и Context Splitting

Если Context часто меняется, это вызывает ререндер всех потребителей:

// Плохо
const AppContext = createContext();
// Любое изменение value ререндерит всё

// Хорошо - разделяем контексты
const UserContext = createContext();
const NotificationContext = createContext();
// Каждый меняется независимо

6. useTransition и useDeferredValue

Делит обновления на срочные и отложенные:

const [isPending, startTransition] = useTransition();
const deferredValue = useDeferredValue(searchQuery);

const handleSearch = (e) => {
  startTransition(() => {
    setResults(filterData(e.target.value));
  });
};

Пользователь видит UI обновления мгновенно, а дорогие вычисления происходят позже.

7. Виртуализация списков

Рендерим только видимые элементы:

import { FixedSizeList } from 'react-window';

<FixedSizeList height={600} itemCount={10000} itemSize={50}>
  {({ index, style }) => (
    <div style={style}>{items[index]}</div>
  )}
</FixedSizeList>

Для 10000 элементов рендерим только примерно 20 видимых.

8. Key в списках

Правильная key помогает React правильно определить изменения:

// Плохо
{items.map((item, index) => <Item key={index} />)}

// Хорошо
{items.map(item => <Item key={item.id} />)}

Инструменты диагностики

  • React DevTools Profiler — видит какие компоненты ререндерятся
  • Why Did You Render — показывает причину ререндера
import whyDidYouRender from '@welldone-software/why-did-you-render';
whyDidYouRender(React);

Component.whyDidYouRender = true;

Принцип оптимизации

  1. Сначала измерь — профилируй код
  2. Потом оптимизируй — не угадывай
  3. Проверь результат — сравни метрики

Большинство приложений работают хорошо без оптимизации. Оптимизируй только узкие места.