Чим React.memo() схожий на shouldComponentUpdate()?
Загальна ідея
І
React.memo(), іshouldComponentUpdate()дозволяють контролювати, чи має компонент перерендерюватися, якщо йогоpropsне змінилися.
Обидва потрібні для оптимізації продуктивності - щоб уникнути зайвих ререндерів, коли компонент отримує ті самі дані.
shouldComponentUpdate() - у класових компонентах
Це метод життєвого циклу, який викликається перед повторним рендером:
class User extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
// повернути false → React пропустить render()
return nextProps.name !== this.props.name;
}
render() {
console.log('рендер');
return <div>{this.props.name}</div>;
}
}Якщо метод повертає:
true-> React викликаєrender()і оновлює компонент;false-> React пропускає рендер і не чіпає DOM.
React.memo() - у функціональних компонентах
Це HOC (Higher-Order Component), який робить для функціональних компонентів те саме, що
shouldComponentUpdateробить для класових.
const User = React.memo(function User({ name }) {
console.log('рендер');
return <div>{name}</div>;
});За замовчуванням React.memo робить поверхневе порівняння пропсів.
Якщо старі і нові пропси ідентичні (за Object.is), компонент не буде перерендерений.
Тобто:
| Компонент | Механізм | Контроль |
|---|---|---|
| Класовий | shouldComponentUpdate(nextProps, nextState) | Повертаєш true / false |
| Функціональний | React.memo(Component, areEqual?) | Другий аргумент - функція порівняння пропсів |
Кастомне порівняння в React.memo
Якщо потрібно - можна явно вказати кастомну логіку порівняння (аналог ручного shouldComponentUpdate):
const User = React.memo(
function User({ name, age }) {
console.log('рендер');
return <div>{name} ({age})</div>;
},
(prevProps, nextProps) => prevProps.age === nextProps.age // Якщо true → не оновлюємо
);Тут функція areEqual(prevProps, nextProps) повертає:
true-> не оновлювати (аналогshouldComponentUpdate = false);false-> оновлювати (аналогshouldComponentUpdate = true).
Пряма відповідність логіки
| Що робить | Класовий варіант | Функціональний варіант |
|---|---|---|
| Перевіряє, чи змінилися props | shouldComponentUpdate() | React.memo() |
| Поверхневе порівняння за замовчуванням | Ні (тільки через PureComponent) | Так, вбудоване в React.memo() |
| Кастомна логіка порівняння | shouldComponentUpdate(nextProps, nextState) | (prevProps, nextProps) => boolean |
| Пропускає ререндер | return false | areEqual() → true |
Приклад: еквівалентний код
Класовий компонент:
class Button extends React.Component {
shouldComponentUpdate(nextProps) {
return nextProps.label !== this.props.label;
}
render() {
console.log('render');
return <button>{this.props.label}</button>;
}
}Функціональний компонент:
const Button = React.memo(
({ label }) => {
console.log('render');
return <button>{label}</button>;
},
(prev, next) => prev.label === next.label
);Поведінка абсолютно однакова.
У чому різниця
| Параметр | shouldComponentUpdate() | React.memo() |
|---|---|---|
| Застосовується до | Класових компонентів | Функціональних компонентів |
| Контроль | Всередині компонента | Ззовні, при обгортанні |
| Порівняння state | Так (через nextState) | Ні (лише props) |
| Можна перевизначити | Так | Так (через areEqual) |
| За замовчуванням поверхневе порівняння | Ні (потрібен PureComponent) | Так |
| Де писати | Всередині класу | Ззовні: React.memo(Component) |
Приклад з оптимізацією
Без оптимізації:
function Parent({ user }) {
return <Child user={user} />;
}
function Child({ user }) {
console.log('render');
return <div>{user.name}</div>;
}Щоразу при новому об'єкті user -> Child перерендерюється.
З React.memo():
const Child = React.memo(({ user }) => {
console.log('render');
return <div>{user.name}</div>;
});Тепер React порівняє старий і новий user ->
якщо посилання те саме, Child не оновиться.
Підсумок
React.memo()≈shouldComponentUpdate()
- обидва потрібні, щоб запобігати зайвим ререндерам, якщо вхідні дані (props) не змінилися.
| Спільна ціль | Поведінка |
|---|---|
| Підвищення продуктивності | Пропуск ререндеру, якщо дані не змінилися |
| Поверхневе порівняння за замовчуванням | Лише у React.memo() і PureComponent |
| Гнучкість через кастомне порівняння | Є в обох |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.