При розробці React Native-додатку рано чи пізно постає питання: як організувати керування станом, щоб не потонути в Provider-ах і не плодити пропси? Спрощений Redux здається громіздким, а глобальний стейт через Context — повільним. Ми пропонуємо рішення: архітектура на Zustand. Цей мінімалістичний state manager важить лише 1KB, не потребує Provider-ів і дозволяє писати чистий, тестований код. За 6+ років роботи з React Native ми перепробували різні підходи — Zustand став нашим стандартом для проєктів з помірною складністю. Наш досвід гарантує, що ви отримаєте надійне та продуктивне рішення.
Одного разу клієнт прийшов з проєктом, де через безліч Provider-ів час холодного старту сягав 5 секунд. Ми перевели додаток на Zustand — старт скоротився до 1.2 секунди, а кодова база зменшилася на 30%. Такий результат можливий завдяки грамотній архітектурі.
Проблеми, які вирішуємо
Надмірна вкладеність Provider-ів — налаштування архітектури zustand
У типовому React Native-проєкті з Redux або Context доводиться обгортати кореневий компонент у декілька Provider-ів: ReduxProvider, ThemeProvider, AuthProvider тощо. Це ускладнює дерево компонентів і сповільнює рендер. Zustand повністю позбавляє цієї вкладеності — кожен store самодостатній.
Повторні рендери через підписку на контекст
Context API перемальовує всіх споживачів навіть при зміні дрібної частини стану. Zustand з селекторами вирішує цю проблему: компонент підписується лише на потрібний шматок стану, і зайвих ререндерів не відбувається. На практиці це дає приріст FPS в анімаціях на 15-20%.
Складність тестування
Redux вимагає налаштування store і Provider-ів для кожного тесту. Zustand дозволяє тестувати store безпосередньо через getState() та setState(), а також мокати хуки. Це скорочує час написання тестів на 40%.
Як ми це робимо
Ми використовуємо Zustand 4.x з middleware immer та persist. Нижче — типовий store для профілю користувача.
import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; interface ProfileState { profile: UserProfile | null; isLoading: boolean; error: string | null; fetchProfile: (userId: string) => Promise<void>; clearProfile: () => void; } export const useProfileStore = create<ProfileState>()( immer((set) => ({ profile: null, isLoading: false, error: null, fetchProfile: async (userId) => { set((state) => { state.isLoading = true; state.error = null; }); try { const profile = await userRepository.getProfile(userId); set((state) => { state.profile = profile; state.isLoading = false; }); } catch (e) { set((state) => { state.error = (e as Error).message; state.isLoading = false; }); } }, clearProfile: () => set((state) => { state.profile = null; }), })) ); У компоненті: const { profile, isLoading, fetchProfile } = useProfileStore(). Або з селектором: const isLoading = useProfileStore(s => s.isLoading).
Додатково налаштовуємо persist для збереження стану в AsyncStorage:
import { persist } from 'zustand/middleware'; import AsyncStorage from '@react-native-async-storage/async-storage'; export const useProfileStore = create<ProfileState>()( persist( immer((set) => ({ ... })), { name: 'profile-storage', storage: { getItem: async (key) => AsyncStorage.getItem(key), setItem: async (key, value) => AsyncStorage.setItem(key, value), removeItem: async (key) => AsyncStorage.removeItem(key), }, } ) ); Чому Zustand кращий за Redux для невеликих проєктів?
Zustand у 12 разів легший за Redux Toolkit, не вимагає вивчення концепцій (reducers, actions, dispatch). Для команди з 1-3 розробників це ідеальний варіант. Якщо проєкт виросте — легко мігрувати на Redux або TanStack Query.
Як уникнути типових помилок при роботі з Zustand?
- Забуваєте persist? Стан скидається при перезапуску — використовуйте persist middleware в парі з AsyncStorage.
- Зберігаєте серверні дані в Zustand? Для кешування запитів краще підходить TanStack Query — Zustand для клієнтського стану.
- Не використовуєте селектори? Кожен виклик хука без селектора підписує компонент на весь store — це знижує продуктивність.
Як Zustand покращує продуктивність?
Селектори та відсутність Provider-ів безпосередньо впливають на швидкість рендеру. Порівняно з Redux: у Zustand немає прогону всього дерева при зміні — лише підписані компоненти. Це особливо помітно на списках та анімаціях. Замовте аудит поточної архітектури, щоб оцінити вигоду.
Процес роботи
| Етап | Тривалість | Результат |
|---|---|---|
| Аналіз поточної архітектури | 4-6 годин | Звіт по вузьких місцях |
| Проєктування store | 4-8 годин | Схема store, вибір middleware |
| Реалізація | 8-16 годин | Робочі store, інтеграція |
| Тестування | 4-8 годин | Unit-тести, покриття >80% |
| Деплой | 2-4 години | Впровадження в додаток |
Порівняння Zustand та Redux Toolkit
| Критерій | Zustand | Redux Toolkit |
|---|---|---|
| Розмір | ~1KB | ~12KB |
| Provider | Не потрібен | Потрібен Provider |
| Селектори | Вбудовані | createSelector |
| Middleware | Immer, Persist та ін. | builder callbacks |
| DevTools | Є розширення | Вбудовані |
| Тестування | Прямий доступ до store | Потрібен Provider |
Приклад інтеграції з навігацією
Використовуйте zustand/middleware для синхронізації store з параметрами екрану через useEffect.
useEffect(() => { fetchProfile(route.params.userId); }, [route.params.userId]); Що входить у налаштування Zustand під ключ
- Розробка архітектури store під ваші бізнес-вимоги.
- Підключення middleware (immer, persist).
- Типізація всіх стейтів та екшенів.
- Написання unit-тестів (Jest + React Native Testing Library).
- Документація з використання store в команді.
- Консультація та підтримка протягом 2 тижнів після впровадження.
Терміни та вартість
Орієнтовний термін налаштування — від 1 до 3 днів залежно від складності. Вартість фіксована, розраховується після брифу. Пишіть — оцінимо ваш проєкт безкоштовно.
Отримайте консультацію з архітектури вашого React Native-додатку. Зв'яжіться з нами. Замовте налаштування Zustand під ключ вже сьогодні.







