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

Почему можно что-нибудь сделать с мутабельными типами данных?

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 проверяет === для определения изменений
// Поэтому нужно создавать новые объекты

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

  1. Используй spread operator для shallow copy: { ...oldObj, name: "Bob" }
  2. Используй spread для массивов: [...oldArr, newItem]
  3. Используй методы array, которые не мутируют: map, filter, slice
  4. Для сложных структур используй immer
  5. Никогда не мутируй props или state напрямую