Этот вопрос проверяет понимание оптимизации рендеринга в React через использование PureComponent и его отличий от обычных компонентов.
PureComponent - это базовый класс в React, который автоматически реализует метод shouldComponentUpdate с поверхностным сравнением пропсов и состояния. Он предотвращает лишние ререндеры компонента, когда пропсы и состояние не изменились, что улучшает производительность приложения.
PureComponent - это оптимизированная версия обычного React.Component, которая автоматически обрабатывает логику предотвращения ненужных ререндеров.
PureComponent автоматически реализует shouldComponentUpdate с поверхностным сравнением (shallow comparison):
javascript
class MyComponent extends React.PureComponent {
render() {
return <div>{this.props.value}</div>;
}
}Обычный Component:
javascript
class RegularComponent extends React.Component {
// Без shouldComponentUpdate - всегда ререндерит
render() {
return <div>{this.props.value}</div>;
}
}PureComponent:
javascript
class OptimizedComponent extends React.PureComponent {
// Автоматически имеет shouldComponentUpdate
// с поверхностным сравнением пропсов и состояния
render() {
return <div>{this.props.value}</div>;
}
}PureComponent сравнивает пропсы и состояние следующим образом:
javascript
// Пример логики поверхностного сравнения
function shallowEqual(objA, objB) {
if (objA === objB) return true;
if (typeof objA !== 'object' || objA === null ||
typeof objB !== 'object' || objB === null) {
return false;
}
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
if (keysA.length !== keysB.length) return false;
for (let i = 0; i < keysA.length; i++) {
if (!objB.hasOwnProperty(keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) {
return false;
}
}
return true;
}javascript
// 1. Компоненты с примитивными пропсами
class UserInfo extends React.PureComponent {
render() {
return (
<div>
<h2>{this.props.name}</h2>
<p>Возраст: {this.props.age}</p>
</div>
);
}
}
// 2. Статические компоненты
class Header extends React.PureComponent {
render() {
return <header>{this.props.title}</header>;
}
}javascript
// 1. Компоненты с часто изменяющимися объектами/массивами
class UserList extends React.PureComponent {
render() {
// Плохо: users всегда новый массив
return this.props.users.map(user =>
<User key={user.id} user={user} />
);
}
}
// 2. Компоненты с функциями в пропсах
class Button extends React.PureComponent {
render() {
// Плохо: onClick всегда новая функция
return <button onClick={this.props.onClick}>Click</button>;
}
}Для функциональных компонентов аналогом PureComponent является React.memo:
javascript
const MyComponent = React.memo(function MyComponent(props) {
return <div>{props.value}</div>;
});
// С кастомной функцией сравнения
const MyComponent = React.memo(
function MyComponent(props) {
return <div>{props.value}</div>;
},
function areEqual(prevProps, nextProps) {
// Возвращает true, если ререндер не нужен
return prevProps.value === nextProps.value;
}
);javascript
// Плохо - создает новый объект каждый раз
this.setState({ user: { ...this.state.user, name: 'Новое имя' } });
// Лучше - если возможно, используйте примитивы
this.setState({ userName: 'Новое имя' });javascript
// Плохо
class Parent extends Component {
handleClick = () => { /* ... */ };
render() {
return <Child onClick={() => {}} />;
}
}
// Хорошо
class Parent extends Component {
handleClick = () => { /* ... */ };
render() {
return <Child onClick={this.handleClick} />;
}
}Вывод: PureComponent следует использовать для компонентов, которые получают примитивные пропсы или редко изменяющиеся объекты. Он автоматически предотвращает ненужные ререндеры через поверхностное сравнение, но требует осторожности с мутируемыми данными и функциями в пропсах.