setUser(user) передаёт ту же ссылку, поэтому React обычно пропустит обновление по Object.is. Мутация уже произошла и может неожиданно проявиться при другом рендере.
Проверка ререндеринга компонента при клике на вторую кнопку в React
setUser(user) передаёт ту же ссылку, поэтому React обычно пропустит обновление по Object.is. Мутация уже произошла и может неожиданно проявиться при другом рендере.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Нужно выяснить, произойдёт ли повторный рендер компонента, когда пользователь нажимает вторую кнопку.
import { useCallback, useEffect, useMemo, useState } from "react";
export function App() {
const [counter, setCounter] = useState(0);
const [user, setUser] = useState({
name: 'Anton',
});
const handleUserClick = () => {
user.name = "Alex";
console.log(user.name);
setUser(user);
};
const increment = () => {
setCounter(counter + 1);
};
const handleBtnClick = useCallback(() => {
increment();
}, []);
return (
<div>
<button onClick={handleBtnClick}>{counter}</button>
<button onClick={handleUserClick}>{user.name}</button>
{/* <button onClick={btnClick2}>Compute Heavy</button> */}
<div />
<input type="text" />
</div>
);
}
Ответ
setUser(user) передаёт ту же ссылку, поэтому React обычно пропустит обновление по Object.is. Мутация уже произошла и может неожиданно проявиться при другом рендере.
Создавайте новый объект и исправьте устаревшее замыкание первой кнопки:
const handleUserClick = () => setUser(previous => ({ ...previous, name: 'Alex' }));
const handleBtnClick = useCallback(() => {
setCounter(previous => previous + 1);
}, []);
Исходный callback с [] помнит increment первого рендера и его counter === 0, поэтому пытается снова установить 1. Функциональный updater не зависит от старого counter. Лог Alex во второй кнопке подтверждает мутацию объекта, но не гарантирует обновления DOM. Неиспользуемые useEffect/useMemo можно убрать из импорта.