Какие знаешь способы оптимизации ререндера?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Оптимизация ререндера в 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;
Принцип оптимизации
- Сначала измерь — профилируй код
- Потом оптимизируй — не угадывай
- Проверь результат — сравни метрики
Большинство приложений работают хорошо без оптимизации. Оптимизируй только узкие места.