Що таке middleware у Zustand?
У Zustand термін middleware (проміжне ПЗ) означає функцію-обгортку, яка розширює поведінку стора, додаючи додаткову логіку між зміною стану (set) і самим її застосуванням.
Якщо простіше:
Middleware у Zustand - це плагіни, які "вбудовуються" в store і додають нові можливості: збереження, логи, devtools, іммутабельність тощо.
Як це працює
Коли ти створюєш store:
import { create } from 'zustand'
const useStore = create((set) => ({
count: 0,
inc: () => set((s) => ({ count: s.count + 1 })),
}))Zustand дозволяє обгорнути цей "чистий" store функцією-міддлварою, щоб змінити або доповнити його поведінку:
import { devtools } from 'zustand/middleware'
const useStore = create(
devtools((set) => ({
count: 0,
inc: () => set((s) => ({ count: s.count + 1 })),
}))
)Тепер Zustand підключається до Redux DevTools, і ти можеш відстежувати стан у браузері.
Популярні middleware у Zustand
| Middleware | Призначення |
|---|---|
devtools | інтеграція з Redux DevTools для відлагодження |
persist | зберігає стан у localStorage, sessionStorage або IndexedDB |
immer | дозволяє змінювати стан "імперативно" через draft (як у Redux Toolkit) |
subscribeWithSelector | підписка тільки на потрібні поля (глибока селективність) |
combine | допомагає об'єднувати декілька зрізів стану в один store |
redux | емулює Redux-подібну поведінку з actions і reducers |
Приклади використання
1. persist
Зберігає стан між перезавантаженнями сторінки:
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
const useAuthStore = create(
persist(
(set) => ({
user: null,
setUser: (user) => set({ user }),
logout: () => set({ user: null }),
}),
{ name: 'auth-storage' } // ключ у localStorage
)
)Тепер дані автоматично зберігатимуться в localStorage.
2. devtools
Додає інтеграцію з Redux DevTools:
import { create } from 'zustand'
import { devtools } from 'zustand/middleware'
const useCounterStore = create(
devtools((set) => ({
count: 0,
inc: () => set((s) => ({ count: s.count + 1 })),
}))
)Тепер можна відкривати DevTools і бачити всі зміни стану.
3. immer
Дозволяє використовувати мутабельний стиль оновлення (через draft):
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 })
}),
}))
)Тут можна "змінювати" масив напряму, ніби це звичайний JS-об'єкт - під капотом Zustand робить іммутабельне копіювання.
4. Комбінування middleware
Можна використовувати декілька міддлвар одночасно - просто вкладай їх:
import { create } from 'zustand'
import { devtools, persist } from 'zustand/middleware'
const useStore = create(
devtools(
persist(
(set) => ({
theme: 'light',
toggleTheme: () => set((s) => ({ theme: s.theme === 'light' ? 'dark' : 'light' })),
}),
{ name: 'theme-storage' }
)
)
)Як middleware влаштоване всередині
Middleware - це функція вищого порядку:
type Middleware = (createState: StateCreator) => StateCreatorВона приймає createState (твою функцію, що створює store)
і повертає нову функцію, яка обгортає або змінює поведінку set, get, subscribe.
Приклад власного middleware:
const logger = (config) => (set, get, api) =>
config(
(args) => {
console.log('Before:', get())
set(args)
console.log('After:', get())
},
get,
api
)Підсумок
| Що робить middleware | Приклад |
|---|---|
| Додає нові функції в store | persist, devtools, immer |
Перехоплює і змінює set() | логування, фільтрація |
| Розширює API стора | методи на кшталт .persist.rehydrate() |
| Можна комбінувати | devtools(persist(...)) |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.