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

Какое сравнение в PureComponent?

2.0 Middle🔥 191 комментариев
#React

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

Какое сравнение в PureComponent

PureComponent — один из способов оптимизации в React, который автоматически предотвращает ненужные перерисовки. Этот вопрос проверяет глубокое понимание механизма сравнения и шаллоу компаресона.

Что такое PureComponent

import React from 'react';

// Обычный Component
class RegularComponent extends React.Component {
  render() {
    return <div>{this.props.name}</div>;
  }
}

// PureComponent - имеет встроенное неглубокое сравнение
class PureComp extends React.PureComponent {
  render() {
    return <div>{this.props.name}</div>;
  }
}

Shallow Comparison (Неглубокое сравнение)

PureComponent использует shallow equality — поверхностное сравнение.

// Shallow comparison работает так:
function shallowEqual(obj1, obj2) {
  // 1. Проверяет типы
  if (typeof obj1 !== typeof obj2) return false;
  
  // 2. Проверяет примитивы
  if (obj1 === obj2) return true;
  
  // 3. Для объектов - сравнивает только первый уровень
  const keys1 = Object.keys(obj1);
  const keys2 = Object.keys(obj2);
  
  if (keys1.length !== keys2.length) return false;
  
  // 4. Сравнивает значения поверхностно
  for (let key of keys1) {
    if (obj1[key] !== obj2[key]) {
      return false; // Используется === для каждого свойства
    }
  }
  
  return true;
}

Как PureComponent сравнивает props и state

PureComponent сравнивает:

  1. Props — поверхностно (shallow)
  2. State — поверхностно (shallow)
class UserCard extends React.PureComponent {
  render() {
    const { user, tags } = this.props;
    return (
      <div>
        <h1>{user.name}</h1>
        <p>Tags: {tags.join(", ")}</p>
      </div>
    );
  }
}

// КЕЙС 1: Примитивные значения
const user1 = { name: "Alice" };
const user2 = { name: "Alice" };
user1 === user2; // false - разные объекты
// PureComponent НЕ перерисуется, если получит user1, потом user2?
// НЕТ! Потому что user1 !== user2

// КЕЙС 2: Одинаковые ссылки
const user = { name: "Alice" };
// Переда user дважды
// PureComponent НЕ перерисуется - потому что === совпадает

// КЕЙС 3: Вложенные объекты
const user = { name: "Alice", address: { city: "NYC" } };
const newUser = { name: "Alice", address: { city: "NYC" } };
// Shallow comparison НЕ сравнит address.city!
// PureComponent ПЕРЕРИСУЕТСЯ, хотя address содержит одинаковые данные

Практические примеры

Пример 1: Работает корректно

class UserProfile extends React.PureComponent {
  render() {
    const { id, name, age } = this.props;
    return <div>{name} ({age})</div>;
  }
}

// Передаем примитивные значения
<UserProfile id={1} name="Alice" age={25} />
// Если id, name, age не изменились - PureComponent НЕ перерисуется

Пример 2: Проблема с объектами

class UserProfile extends React.PureComponent {
  render() {
    const { user } = this.props;
    return <div>{user.name}</div>;
  }
}

function Parent() {
  const [count, setCount] = useState(0);
  
  // ПРОБЛЕМА: новый объект создается при каждом рендере
  const user = { name: "Alice" }; // новая ссылка каждый раз!
  
  return (
    <div>
      <UserProfile user={user} />
      {/* UserProfile ВСЕГДА перерисуется,
          потому что user - новый объект */}
      <button onClick={() => setCount(count + 1)}>Update</button>
    </div>
  );
}

Пример 3: Решение проблемы

function Parent() {
  const [count, setCount] = useState(0);
  
  // Используем useMemo для стабильной ссылки
  const user = useMemo(() => ({ name: "Alice" }), []);
  
  return (
    <div>
      <UserProfile user={user} />
      {/* UserProfile НЕ перерисуется, потому что ссылка на user стабильна */}
      <button onClick={() => setCount(count + 1)}>Update</button>
    </div>
  );
}

Сравнение !== и ==="

PureComponent использует === для сравнения:

// === сравнивает ссылки для объектов
const obj1 = { a: 1 };
const obj2 = { a: 1 };

obj1 === obj2; // false - разные ссылки
obj1.a === obj2.a; // true - одинаковые значения

// Shallow сравнение проходит ВСЕ уровни второго порядка
const obj1 = { a: 1, b: 2 };
const obj2 = { a: 1, b: 2 };
shallowEqual(obj1, obj2); // true - все свойства === совпадают

// Но вложенные объекты сравниваются по ссылке
const obj1 = { a: 1, nested: { x: 1 } };
const obj2 = { a: 1, nested: { x: 1 } };
shallowEqual(obj1, obj2); // false - nested !== nested

Различие: Component, PureComponent, memo

// 1. Component - всегда перерисовывается
class MyComponent extends React.Component {
  render() {
    return <div>{this.props.value}</div>;
  }
}
// Перерисуется при ЛЮБОМ изменении родителя

// 2. PureComponent - shallow сравнение props/state
class MyPureComponent extends React.PureComponent {
  render() {
    return <div>{this.props.value}</div>;
  }
}
// Перерисуется только если props/state изменились (shallow)

// 3. React.memo - функциональный компонент с shallow сравнением
const MyMemoComponent = React.memo(function MyComponent({ value }) {
  return <div>{value}</div>;
});
// Перерисуется только если props изменились (shallow)

// 4. React.memo с custom компаратором
const MyMemoComponent = React.memo(
  function MyComponent({ value, nested }) {
    return <div>{value}</div>;
  },
  (prevProps, nextProps) => {
    // Возвращает true если пропсы равны (НЕ перерисовывать)
    return prevProps.value === nextProps.value;
  }
);

Когда PureComponent неэффективен

class DataTable extends React.PureComponent {
  render() {
    const { data } = this.props;
    return (
      <div>
        {data.map(item => <div key={item.id}>{item.name}</div>)}
      </div>
    );
  }
}

function Parent() {
  const [count, setCount] = useState(0);
  
  // ПРОБЛЕМА: массив пересоздается при каждом рендере
  const data = [
    { id: 1, name: "Item 1" },
    { id: 2, name: "Item 2" }
  ];
  
  return (
    <div>
      <DataTable data={data} />
      {/* DataTable ВСЕГДА перерисуется,
          потому что data - новый массив */}
      <button onClick={() => setCount(count + 1)}>Update</button>
    </div>
  );
}

Решение: использование useMemo

function Parent() {
  const [count, setCount] = useState(0);
  
  // Мемоизируем данные
  const data = useMemo(() => [
    { id: 1, name: "Item 1" },
    { id: 2, name: "Item 2" }
  ], []); // Пустой deps - создается один раз
  
  return (
    <div>
      <DataTable data={data} />
      {/* DataTable НЕ перерисуется */}
      <button onClick={() => setCount(count + 1)}>Update</button>
    </div>
  );
}

Производительность shallow сравнения

const obj1 = { a: 1, b: 2, c: 3, d: 4, e: 5 };
const obj2 = { a: 1, b: 2, c: 3, d: 4, e: 5 };

// Shallow сравнение проверяет каждое свойство один раз
// O(n) где n - количество свойств
// Обычно это очень быстро для небольших объектов

// Глубокое сравнение было бы:
// O(n * m) где m - средняя глубина
// Значительно медленнее

Лучшие практики

  1. Используй PureComponent для оптимизации компонентов, которые часто перерисовываются
  2. Остерегайся новых объектов/массивов — используй useMemo/useCallback
  3. Помни о shallow сравнении — вложенные объекты сравниваются по ссылке
  4. Для функциональных компонентов используй React.memo вместо PureComponent
  5. Профилируй перед оптимизацией — не оптимизируй без необходимости
  6. Используй custom компаратор в memo если shallow сравнения недостаточно

PureComponent — мощный инструмент, но требует понимания shallow сравнения и правильного управления ссылками на объекты и массивы.

Какое сравнение в PureComponent? | PrepBro