Yours Truly, Famous Inc.
Забудьте все, что вы знали о стейт-менеджерах прежде.
А кто его не писал?
Состояние приложения хранилось во множестве глобальных переменных
Преимущества: простота
Недостатки: главным недостатком является не боль в пальцах при поддержке такого кода, а то, что глобальные переменные никогда не удаляются из памяти, их много и они не связаны логически между собой!
Понятие бизнес-логики изменения состояния отсутствует
Состояние приложения хранится в одном объекте типа appConfig
Преимущества: состояние оформлено в одну сущность
Недостатки:
Теория
Состояние приложения хранится в модели
Преимущества:
Реальность
Состояние приложения хранится в модели
Недостатки:
Однонаправленный поток данных
Создание однонаправленного контролируемого и предсказуемого потока данных: представления -> канал данных -> модели -> представления
Для того, чтобы различать данные для разных сторов (моделей) в канале - данные снабдили метаданными и назвали этот тип данных Action
Однонаправленный поток данных
Однонаправленный поток данных
Преимущества:
Однонаправленный поток данных
Недостатки:
Это - Flux с единым стором и логикой по его обновлению
Изменения:
весь зопарк сторов с их не прозрачной логикой обновления заменили единым стором (полная аналогия с БД) и централизованной чистой логикой его изменения.
Добавили middleware для обработки бизнес-логики и сайд-эффектов
Это - Flux с единым стором и логикой по его обновлению
Это -Flux с единым стором и логикой по его обновлению
Преимущества:
Это -Flux с единым стором и логикой по его обновлению
Недостатки:
Чего удалось достичь:
Чего не удалось достичь:
Небольшое, быстрое и масштабируемое решение для управления состоянием, основанное на принципах Flux и immutable state (как и React).
view --> event handlers --> store --> react hook --> view
В его основе лежит хранилище основанное на базе publish/subscribe.
Имеет удобный API, основанный на единственном хуке, не создает лишнего шаблонного кода и не навязывает жестких правил использования.
Не имеет проблем с Zombie children и context loss и отлично работает с React concurrency mode
const storeHook = create((set, get) => { store_config })
storeHook: (selector) => selectedState
selector: (state) => ({ извлечённые данные из state })
Хук имеет статические методы:storeHook.getState: () => state
storeHook.setState: (newState) => void
storeHook.subscribe: (callback) => void
Как и в Redux вы можете написать для хранилища свои middleware, которые будут обрабатывать события и изменять состояние хранилища.
Zustand предлагает в пакете такие middleware как:
Используя статические методы хука:
вы получаете доступ к стору из любого окружения: как из методов стора, обработчиков событий React компонент, так и из vanilla JavaScript.
При этом вы свободно можете использовать асинхронную обработку данных и любые сайд-эффекты!💥💥💥
Всего 4 простых метода:
Если даже с параметрами ваш селектор может возвращать новый объект - оберните селектор в 2 хука: useCallback и useShallow
Используем механизм подписок без лишних перерисовок
А ведь Pub/sub был в MV* с незапамятных времен - нам оставалось лишь выделить
в абстракцию селектор, объединить все модели в один стор и оформить
аналог хука (и это легко реализуется на нативном js)!
Так иногда бывает в индустрии - чтобы прийти к верному решению порой приходится делать технологический крюк и потратить на это годы!
В последнее время у новичков, кто руками не проходил стадию развития с использованием MV*, наблюдается тенденция наступать на те грабли, что индустрия уже давно прошла: model hell - появляются различные амёбные, молекулярные, атомные и кварковые "стейт-менеджеры"
Использование отдельных хранилищь оправдано лишь:
* - когда реально нет пересечений запросов к этим сущностям
Вопреки примерам из документации, рекомендую не создавать методы хранилища внутри него - если у вас в хранилище много сущностей или сущности сложные, а их методы обработки достаточно объемные - описание вашего хранилища станет не читаемым, не понимаемым и плохо поддерживаемым.
Если хотите иметь надежное приложение с минимумом багов - никогда!, никогда не давайте доступ к хранилищу разрабочкикам в обход его методов!
Проблема подавляющего большинства проектов заключается в том, что никто не соблюдает правило единственной отвественности - логика валидации и изменения данных размазана по всему коду, а хранилище используется исключительно как хранилище json! Отсюда и 99% багов в приложении.
Хранилище должно валидировать данные на входе, сериализивать их, проверить ссылочную целостность внутри и только после этого обновлять и отдать их обратно замороженными от изменений - только в этом случае вы получите не убиваемое ядро приложения и надежное приложение!
Инкапсуляция бизнес-логики в методах стора позволит безболезненно менять стейт-менеджер - приложение использует только методы сторов!
Перевод проекта с Redux на Zustand произошел очень быстро и без проблем - благодаря сходству семантики в обоих подходах при переходе не возникало никаких проблем.
Параллельно хранилищу Redux было создано хранилище Zustand и постепенно все сущности без боли переносились в новый стор.
Сказать о том, что разработка с Zustand упростилась - это не сказать ничего!
Благодаря Zustand вся логика, связанная с доменными сущностями была собрана в хранилище. Используя Zustand вместе с "адаптивной слоёной архитектурой" мы почти избавились от тестов (мы пишем их по минимуму) - в коде практически не осталось места для багов!
Мы отдали на откуп джунов создание визуала - они создают
компоненты, логику отображения и сражаются со storybook - данные же
подключаются к компонентам парой строчек в контейнерах!
Код проекта стал структурированным, простым и понимаемым, а в проекте
мы практически избавились от багов!
Начинайте активно в своих проектах переходить на самый простой, самый современный и самый быстрый стейт-менеджер - он существует уже несколько лет! Сделайте себе и людям хорошо!
Используйте Zustand совместно с правильной архитектурой приложения и будет вам счастье!