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

Вызовется ли перерендер, если изменить поле объекта пропса

2.0 Middle🔥 171 комментариев
#JavaScript Core

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

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

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

Перерендер при изменении поля объекта пропса

Краткий ответ

Нет, перерендер НЕ вызовется, если вы просто измените поле объекта пропса без изменения самой ссылки на объект. React использует shallow comparison для пропсов — он сравнивает ссылки объектов, а не их содержимое.

Как работает сравнение пропсов

React сравнивает пропсы поверхностно. Для объектов это означает проверку ===/reference equality, а не deep equality:

const obj1 = { name: "Alice" };
const obj2 = { name: "Alice" };

console.log(obj1 === obj2); // false — разные ссылки!
console.log(obj1 === obj1); // true — одна ссылка

Если родитель передаёт пропс и ничего не меняет (ссылка остаётся той же), React считает, что пропс не изменился.

Пример: почему перерендера НЕ будет

// Родитель
function Parent() {
  const userData = { name: "Bob", age: 25 };

  const handleClick = () => {
    userData.age = 26; // Изменяем СОДЕРЖИМОЕ, но не ссылку
  };

  return (
    <div>
      <button onClick={handleClick}>Увеличить возраст</button>
      <Child user={userData} />
    </div>
  );
}

// Ребёнок
function Child({ user }) {
  console.log("Child рендерится");
  return <p>Возраст: {user.age}</p>;
}

В этом примере:

  • Клик на кнопку изменяет userData.age на 26
  • Но ссылка на объект userData остаётся одной и той же
  • React видит, что userData === userData (старый пропс === новый пропс)
  • Перерендер НЕ произойдёт -> <p> всё ещё показывает 25

Это опасная ситуация! Данные в памяти изменились, но UI не обновился.

Что нужно делать: создавайте НОВЫЙ объект

Для триггера перерендера нужно создать новый объект (новую ссылку):

const handleClick = () => {
  userData = { ...userData, age: 26 }; // Spread operator создаёт новый объект
  // или
  userData = Object.assign({}, userData, { age: 26 });
};

Теперь React видит разные ссылки -> сравнивает пропсы -> находит, что user изменился -> перерендерит.

С useState (правильный способ)

В реальных приложениях используйте useState для управления состоянием:

function Parent() {
  const [userData, setUserData] = useState({ name: "Bob", age: 25 });

  const handleClick = () => {
    setUserData({ ...userData, age: 26 }); // Создаём новый объект
  };

  return (
    <div>
      <button onClick={handleClick}>Увеличить возраст</button>
      <Child user={userData} />
    </div>
  );
}

Дополнительные методы для обновления

Spread operator:

setUser({ ...user, age: 26 });

Object.assign:

setUser(Object.assign({}, user, { age: 26 }));

Immer (библиотека для удобства):

setUser(produce(user, draft => {
  draft.age = 26;
}));

Вложенные объекты

Для вложенных объектов нужно создавать новые объекты на КАЖДОМ уровне:

const user = { name: "Bob", address: { city: "Moscow", zip: "101000" } };

// Неправильно — ребёнок (address) не изменился
const wrongUpdate = { ...user, address: { ...user.address, zip: "102000" } };

// Правильно
const correctUpdate = { 
  ...user, 
  address: { ...user.address, zip: "102000" } 
};

Практический вывод

  • Изменение содержимого объекта БЕЗ изменения ссылки -> перерендер НЕ произойдёт
  • Для триггера перерендера нужна новая ссылка (новый объект)
  • Всегда используйте setState для изменения состояния в React
  • Никогда не мутируйте пропсы или состояние напрямую
  • Инструменты вроде Immer помогают избежать ошибок при работе со сложными структурами
Вызовется ли перерендер, если изменить поле объекта пропса | PrepBro