Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Новий об'єкт під час оновлення стану». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**React** не відстежує внутрішні зміни об'єктів, а визначає, чи змінився стан, за посиланням на об'єкт. **Ключове:** якщо ти мутуєш старий об'єкт напряму, React думає, що стан не змінився, і не перемальовує компонент.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Коротка відповідь Тому що React **не відстежує внутрішні зміни об'єктів**, а **визначає, чи змінився стан**, за **посиланням на об'єкт**. Якщо ти мутуєш (змінюєш) старий об'єкт напряму, React думає, що стан не змінився, і не перемальовує компонент. --- ## 1. Що відбувається, коли ти робиш так: ```javascript const [user, setUser] = useState({ name: "Alex", age: 25 }); function updateName() { user.name = "Tim"; // mutating the object directly setUser(user); } ``` Що бачить React: - Старе посилання: 0xA12F - Нове посилання: 0xA12F (те саме, адже об'єкт не створювався заново) - React порівнює посилання і вирішує: "Об'єкт той самий, отже, змін немає." Результат: компонент не перерендериться, UI залишиться старим, попри зміну даних. --- ## 2. Правильний спосіб - створити новий об'єкт ```javascript setUser({ ...user, name: "Tim" }); ``` Що тепер відбувається: - Старий об'єкт -> 0xA12F - Новий об'єкт -> 0xB83C (у нього та сама структура, але інше посилання) - React порівнює посилання і розуміє: "Це новий об'єкт, потрібно оновити компонент." Компонент ререндериться, UI оновлюється. --- ## 3. Чому React порівнює посилання, а не значення React використовує поверхневе (shallow) порівняння, щоб визначити, чи потрібно оновлювати компонент: ```javascript oldState === newState ``` Він не робить глибокого порівняння (deep equal), інакше це було б надто повільно для великих об'єктів. Тому React визначає зміну стану за зміною посилання (вказівника). Якщо посилання на об'єкт змінилося, стан новий, оновлюємо UI. --- ## 4. Приклад із масивом Той самий принцип для масивів: Погано: ```javascript items.push("new"); // mutating the array setItems(items); ``` Добре: ```javascript setItems([...items, "new"]); // creating a new array ``` React бачить нове посилання на масив і оновлює компонент. --- ## 5. Чому мутація - це ще й логічна помилка Якщо ти мутуєш старий стан, то: - старі посилання (у замиканнях, хуках, props, ефектах) тепер вказують на змінені дані - це ламає передбачуваність, - React може «думати», що стан старий, і не викликати потрібні ефекти, - devtools і time-travel debugging стають неможливими (не можна «відкотити» стан назад, якщо він мутований). --- ## 6. Приклад наочно ```javascript function UserCard() { const [user, setUser] = useState({ name: "Alex", age: 25 }); const handleClick = () => { // Direct mutation user.age++; setUser(user); // won't work }; const handleClickCorrect = () => { // Immutable update setUser(prev => ({ ...prev, age: prev.age + 1 })); }; console.log("Re-render:", user); return ( <> <p>{user.name} - {user.age}</p> <button onClick={handleClick}>Bad</button> <button onClick={handleClickCorrect}>Good</button> </> ); } ``` При натисканні на «Bad» React не перерендериться, а при «Good» - оновить UI як потрібно. --- ## Підсумок | Поведінка | Пряма мутація | Копіювання ({ ...obj }) | |---|---|---| | Змінюється посилання | Ні | Так | | React бачить зміну | Ні | Так | | Відбувається ререндер | Ні | Так | | Передбачуваність | Ламається | Зберігається | | Підтримка DevTools / time travel | Неможлива | Можлива | --- ### Підсумкова думка: > У React стан має бути іммутабельним (незмінюваним). Завжди створюй новий об'єкт або масив замість зміни старого - тоді React зможе коректно визначити, що стан змінився, і оновити інтерфейс.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.