← Назад к вопросам
Почему можно что-нибудь сделать с мутабельными типами данных?
1.0 Junior🔥 182 комментариев
#Soft Skills и рабочие процессы
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое мутабельные типы данных?
Мутабельные (изменяемые) типы данных — это те, которые можно изменять после создания. В JavaScript к ним относятся объекты, массивы и функции. Проблемы с мутабельными типами часто возникают при работе с состоянием в React, когда изменения не отслеживаются корректно.
Проблема 1: Случайные мутации и побочные эффекты
// Неправильно: мутирование объекта напрямую
const user = { name: "Alice", age: 25 };
function updateUserAge(user, newAge) {
user.age = newAge; // Мутируем оригинальный объект!
return user;
}
const updatedUser = updateUserAge(user, 30);
console.log(user.age); // 30 (изменился!)
console.log(updatedUser.age); // 30
console.log(user === updatedUser); // true (это ОДИН объект!)
Проблема 2: React не обнаруживает изменения состояния
// Неправильно в React: мутация state не вызывает re-render
function UserProfile() {
const [user, setUser] = useState({ name: "Alice", age: 25 });
const handleAgeChange = (newAge) => {
user.age = newAge;
setUser(user); // React не видит изменений!
};
return (
<div>
<p>Age: {user.age}</p>
<button onClick={() => handleAgeChange(30)}>Update Age</button>
</div>
);
}
// Правильно: создаём новый объект
function UserProfile() {
const [user, setUser] = useState({ name: "Alice", age: 25 });
const handleAgeChange = (newAge) => {
setUser({ ...user, age: newAge });
};
return (
<div>
<p>Age: {user.age}</p>
<button onClick={() => handleAgeChange(30)}>Update Age</button>
</div>
);
}
Проблема 3: Вложенные объекты и массивы
// Неправильно: мутируем вложенный объект
function App() {
const [data, setData] = useState({
user: { name: "Alice" },
posts: [{ id: 1, comments: [{ id: 1, text: "Great!" }] }]
});
const updateComment = (postId, newText) => {
data.posts[0].comments[0].text = newText; // МУТАЦИЯ!
setData(data); // React не видит изменений
};
// Правильно: deep copy
const updateCommentCorrect = (postId, newText) => {
setData({
...data,
posts: data.posts.map(post =>
post.id === postId
? {
...post,
comments: post.comments.map(comment => ({
...comment,
text: newText
}))
}
: post
)
});
};
}
Проблема 4: Array методы, которые мутируют
// Неправильные методы (мутируют оригинальный массив):
const arr = [1, 2, 3];
arr.push(4); // Добавляет в оригинальный массив
arr.pop(); // Удаляет
arr.splice(0, 1); // Удаляет
arr.sort(); // Сортирует
arr.reverse(); // Разворачивает
// Правильные методы (создают новый массив):
const newArr = [...arr, 6]; // spread operator
const withoutFirst = arr.slice(1); // slice
const mapped = arr.map(x => x * 2); // map
const filtered = arr.filter(x => x > 2); // filter
Пример в React: TODO список
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: "Learn React", done: false }
]);
// Добавить
const addTodo = (text) => {
setTodos([...todos, { id: Date.now(), text, done: false }]);
};
// Удалить
const removeTodo = (id) => {
setTodos(todos.filter(todo => todo.id !== id));
};
// Обновить
const updateTodo = (id, newText) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, text: newText } : todo
));
};
// Отметить как выполненное
const toggleTodo = (id) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, done: !todo.done } : todo
));
};
return (
<div>
{todos.map(todo => (
<div key={todo.id}>
<input
type="checkbox"
checked={todo.done}
onChange={() => toggleTodo(todo.id)}
/>
<span>{todo.text}</span>
<button onClick={() => removeTodo(todo.id)}>Delete</button>
</div>
))}
<button onClick={() => addTodo("New Todo")}>Add</button>
</div>
);
}
Почему React требует иммутабельности?
const obj1 = { name: "Alice" };
const obj2 = obj1; // То же самое
const obj3 = { name: "Alice" }; // Новый объект
obj1 === obj2; // true (одна ссылка)
obj1 === obj3; // false (разные ссылки)
// React проверяет === для определения изменений
// Поэтому нужно создавать новые объекты
Лучшие практики
- Используй spread operator для shallow copy:
{ ...oldObj, name: "Bob" } - Используй spread для массивов:
[...oldArr, newItem] - Используй методы array, которые не мутируют:
map, filter, slice - Для сложных структур используй immer
- Никогда не мутируй props или state напрямую