Що робить middleware immer?
immer - одне з найкорисніших middleware в Zustand, і воно робить роботу зі станом простішою, безпечнішою і зручнішою, особливо якщо ти не хочеш вручну стежити за іммутабельністю.
Суть в одному реченні
immer-middleware дозволяє змінювати стан "як ніби напряму", але під капотом Zustand усе одно створює іммутабельну копію (тобто не мутує оригінал).
Без immer
У звичайному Zustand ти маєш явно повертати новий об'єкт, щоб React зрозумів, що стан змінився:
import { create } from 'zustand'
const useTodoStore = create((set) => ({
todos: [],
addTodo: (text) =>
set((state) => ({
todos: [...state.todos, { text, done: false }],
})),
}))Тут важливо не мутувати state.todos, інакше React не побачить змін.
Тобто не можна робити state.todos.push(...).
З immer
З immer ти можеш писати код у мутабельному стилі, а бібліотека під капотом створить іммутабельну копію:
import { create } from 'zustand'
import { immer } from 'zustand/middleware/immer'
const useTodoStore = create(
immer((set) => ({
todos: [],
addTodo: (text) =>
set((state) => {
state.todos.push({ text, done: false }) // можна мутувати!
}),
toggleTodo: (index) =>
set((state) => {
state.todos[index].done = !state.todos[index].done
}),
}))
)Тепер Zustand автоматично:
- створює "чернетку" стану (
draft); - застосовує до неї твої зміни;
- створює нову версію стану без мутацій.
Як це працює під капотом
immer використовує бібліотеку Immer, яка реалізує концепцію immutable state через Proxy.
Приблизно так:
- Zustand створює проксі-об'єкт (
draft) стану; - Ти "мутуєш" його як звичайний об'єкт;
- Immer фіксує зміни і створює нову іммутабельну копію стану.
Переваги
| Перевага | Опис |
|---|---|
| Чистий код | Пишеш у природному стилі без копіювання масивів і об'єктів |
| Безпека | Гарантує іммутабельність (оригінал не мутується) |
| Простота | Не потрібно вручну використовувати спреди (...) |
| Сумісність | Працює з persist, devtools та іншими middleware |
Важливо пам'ятати
- Immer трохи повільніший за "чисті" іммутабельні оновлення, якщо оновлення дуже часті (наприклад, 60 разів на секунду в анімації). Але у звичайних застосунках різниця непомітна.
- Immer не можна використовувати разом із прямими мутаціями поза
set()- він працює лише всередині функціїset((state) => { ... }).
Підсумок
| Параметр | Без immer | З immer |
|---|---|---|
| Оновлення масиву | set({ todos: [...state.todos, newTodo] }) | set((s) => { s.todos.push(newTodo) }) |
| Іммутабельність | вручну | автоматично |
| Код | громіздкий | лаконічний |
| Безпека | залежить від розробника | гарантується Immer |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.