В этой статье основное внимание уделяется поведению immer.js в различных условиях. Обладая этими знаниями, вы будете знать, как можно оптимизировать производительность современного reduxпри использовании createSliceдля редьюсеров записи (поскольку он использует immer.js за сценой для изменения состояний).

Разминка: ничего не меняйте

Когда вы ничего не изменяете с помощью функции produce, она возвращает ЖЕ эталонный объект.

import produce from "immer";
const users = [
  { id: 1, username: "Jerry" },
  { id: 2, username: "Tom" }
];
const nextUsers = produce(users, (draft) => {});
console.log(nextUsers === users); // true

Изменение массива объектов

Когда вы изменяете поле объекта внутри массива с помощью функции produce, происходят следующие эффекты:

  1. Создается новая ссылка на измененный вами объект.
  2. Вложенные объекты не затрагиваются. Он сохранит ту же ссылку.
  3. Будет создана новая ссылка на массив, содержащий этот объект.
  4. Однако, исходя из 3, элементы массива, которые не изменены, сохранят ту же ссылку.
import produce from “immer”;
const users = [
  { id: 1, username: “Jerry”, settings: { notification: true } },
  { id: 2, username: “Tom”, settings: { notification: false } }
];
const nextUsers = produce(users, (draft) => {
  draft[1].username = “Tom Am”;
});
console.log(nextUsers[1] === users[1]);  // 1. false
console.log(nextUsers[1].settings === users[1].settings); // 2. true
console.log(nextUsers === users); // 3. false
console.log(nextUsers[0] === users[0]); // 4. true

Немного изменим программу:

const users = [
  { id: 1, username: “Jerry”, hobbies: ["music", "sports"] },
  { id: 2, username: “Tom”, hobbies: ["drama", "arts"] },
];
const nextUsers = produce(users, (draft) => {
  draft[1].hobbies[0] = "economics";
});
console.log(nextUsers[1] === users[1]);  // 1. false
console.log(nextUsers[1].hobbies === users[1].hobbies); // 2. false
console.log(nextUsers === users); // 3. false
console.log(nextUsers[0] === users[0]); // 4. true

Вышеприведенная программа изменена, чтобы изменить элемент массива объекта внутри массива. Это будет иметь следующий эффект:

  1. Создается новая ссылка на измененный вами объект.
  2. Создается новая ссылка измененного массива.
  3. Будет создана новая ссылка на массив, содержащий этот объект.
  4. Однако, исходя из 3, элементы массива, которые не изменены, сохранят ту же ссылку.

Используя приведенные выше знания, вы могли бы спроектировать хранилище redux с эффективными редукторами, которые могли бы предотвратить ненужный повторный рендеринг!