← Назад к вопросам
Как компонент понимает, перерисовались ли пропсы?
1.3 Junior🔥 111 комментариев
#React
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как компонент узнает об изменении props
В React компоненты перерисовываются (re-render) когда их props изменяются. Это один из ключевых механизмов React. Рассказу, как это работает под капотом и как контролировать это поведение.
1. Базовый механизм - сравнение props
React автоматически отслеживает изменения props:
function Button({ label, onClick }) {
console.log('Button rendered with label:', label);
return (
<button onClick={onClick}>
{label}
</button>
);
}
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
{/* Первый рендер: label="Click me" */}
<Button label="Click me" onClick={() => setCount(count + 1)} />
{/* Когда count меняется, props МЕНЯЮТСЯ */}
{/* React видит: label остался тем же, но onClick теперь ДРУГАЯ функция */}
{/* Компонент Button перерендерится */}
</div>
);
}
2. Как React сравнивает props
React использует поверхностное сравнение (shallow comparison):
// Это РАЗНЫЕ функции - React считает их разными
const func1 = () => console.log('A');
const func2 = () => console.log('A');
console.log(func1 === func2); // false
// Это ОДА функция - React считает их одинаковыми
const func = () => console.log('A');
const refFunc = func;
console.log(func === refFunc); // true
// Для объектов - сравнивает только ссылку, не содержимое
const obj1 = { name: 'Alice' };
const obj2 = { name: 'Alice' };
console.log(obj1 === obj2); // false (разные ссылки)
const obj3 = obj1;
console.log(obj1 === obj3); // true (одна ссылка)
3. useEffect для отслеживания изменения props
Усе useEffect с массивом зависимостей (dependency array):
function Card({ title, description, userId }) {
// Выполнится при ЛЮБОМ изменении компонента
console.log('Card rendered');
// Выполнится только когда title или description меняются
useEffect(() => {
console.log('Title or description changed:', title, description);
}, [title, description]);
// Выполнится только когда userId меняется
useEffect(() => {
console.log('Fetching user data for userId:', userId);
// Здесь обычно делают fetch запрос
}, [userId]);
// Выполнится один раз при монтировании
useEffect(() => {
console.log('Component mounted');
return () => {
console.log('Component unmounted');
};
}, []);
return (
<div>
<h2>{title}</h2>
<p>{description}</p>
</div>
);
}
4. Отслеживание ВСЕХ изменений props
function MyComponent(props) {
// Выполнится КАЖДЫЙ раз когда какой-то prop меняется
useEffect(() => {
console.log('Some prop changed');
console.log('Current props:', props);
}); // Нет dependency array - выполняется при каждом рендере!
// ПРАВИЛЬНО - отслеживать конкретные props
useEffect(() => {
console.log('Props changed');
}, [props.id, props.title, props.data]);
return <div>Component</div>;
}
5. React.memo - оптимизация перерендеров
Если хотите избежать перерендера при неизменных props, используйте React.memo:
// Компонент БЕЗ оптимизации
function Button({ label, onClick }) {
console.log('Button rendered');
return <button onClick={onClick}>{label}</button>;
}
// Компонент С оптимизацией
const OptimizedButton = React.memo(function Button({ label, onClick }) {
console.log('Button rendered');
return <button onClick={onClick}>{label}</button>;
});
function Parent() {
const [count, setCount] = useState(0);
const [other, setOther] = useState('text');
// Каждый рендер - новая функция
const handleClick = () => setCount(count + 1);
return (
<div>
{/* При изменении other Button перерендерится ВСЕ РАВНО */}
{/* Потому что onClick - новая функция каждый раз */}
<OptimizedButton label="Click" onClick={handleClick} />
<button onClick={() => setOther('new text')}>Change other</button>
</div>
);
}
6. useCallback для стабилизации функций
Для React.memo нужны стабильные props:
const OptimizedButton = React.memo(({ label, onClick }) => {
console.log('Button rendered');
return <button onClick={onClick}>{label}</button>;
});
function Parent() {
const [count, setCount] = useState(0);
const [other, setOther] = useState('text');
// useCallback мемоизирует функцию
// Функция пересоздается ТОЛЬКО если count меняется
const handleClick = useCallback(() => {
setCount(count + 1);
}, [count]); // Зависимость: count
// Или если функция не зависит от state
const handleStable = useCallback(() => {
console.log('Clicked');
}, []); // Никогда не пересоздается
return (
<div>
{/* Теперь при изменении other Button НЕ перерендерится */}
<OptimizedButton label="Click" onClick={handleClick} />
<button onClick={() => setOther('new text')}>Change other</button>
</div>
);
}
7. useMemo для сложных объектов
То же самое для объектов и массивов:
const OptimizedCard = React.memo(({ user, settings }) => {
console.log('Card rendered');
return <div>{user.name}</div>;
});
function Parent() {
const [count, setCount] = useState(0);
// ПЛОХО - новый объект при каждом рендере
const user = { name: 'Alice', id: 1 }; // Новый объект!
// ХОРОШО - мемоизированный объект
const memoizedUser = useMemo(
() => ({ name: 'Alice', id: 1 }),
[] // Пересоздается только если зависимости меняются
);
return (
<div>
<OptimizedCard user={memoizedUser} />
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
8. Пользовательское сравнение props
Можно определить собственную логику сравнения:
function UserProfile({ id, name, age }) {
return <div>{name}, {age}</div>;
}
// Стандартное сравнение - re-render если хоть что-то изменилось
const Memoized = React.memo(UserProfile);
// Пользовательское сравнение
const CustomMemo = React.memo(
UserProfile,
(prevProps, nextProps) => {
// Вернуть true = не перерендерить (props одинаковые)
// Вернуть false = перерендерить (props изменились)
return (
prevProps.name === nextProps.name &&
prevProps.age === nextProps.age
// Игнорируем id
);
}
);
9. DevTools для отслеживания
Используйте React DevTools для отладки:
// 1. Установите React DevTools browser extension
// 2. DevTools -> Profiler
// 3. Запишите взаимодействие
// 4. Посмотрите какие компоненты перерендерились
// 5. На вкладке "Ranked chart" видны самые медленные
// Или добавьте логирование
function MyComponent(props) {
console.log('Rendered with props:', props);
return (
<div>
{/* Если видите одно и то же дважды - бесполезный re-render */}
</div>
);
}
Чеклист отслеживания изменений props
- useEffect с зависимостями для отслеживания
- React.memo для оптимизации компонентов
- useCallback для стабильных функций
- useMemo для сложных объектов
- DevTools для профилирования
- Избегайте создания объектов/функций в render
- Не забывайте про пустой dependency array []
- Тестируйте на производительность
Понимание этого механизма критично для написания эффективного React кода!