Comments 53
Не знаю можно ли найти реализацию еще меньше чем эта.
https://github.com/nanostores/nanostores вроде может потягаться
по размеру - да возможно
полностью не изучал но по диагонали пробежался - да приблизительно похожая реализация за исключением того, что сама идеология атомов, молекул и кварков в принципе не верная
- зачем выносить, к примеру, состояние счетчика из компонента в какой-то атом?
- атомы, молекулы кварки если они в реальности связанные сущности придется связывать кодом между собой, код будет размазан, поток данных будет разнонаправленным и не контролируемым и не читаемым - в общем получим классический model hell из MVC
сама идеология атомов, молекул и кварков в принципе не верная
Кажется, это называется "зашоренность", вести тут дискуссию нет смысла.
не согласен - это называется "опыт" :)
когда подхватите один раз зацикленность изменений и просидите в отладке пару дней пытаясь во всем коде приложения ставить брейкпоинты для того, чтобы найти где же произошло зацикливание - сразу же измените мнение.
Мы это уже проходили в Bacbone.js и в Marionette.js и других подобных фреймворках ну и до этого в голом MVC
рекомендую почитать почему индустрия от FLUX перешла на REDUX - там как раз про это
Во FLUX был однонаправленный поток но не было единого хранилища - и все баги которые возникали - это были баги и проблемы в коде, который связывал разные сторы: ожидание изменений, проверка целостности данных, разнонаправленный поток изменений ...
Атомы идут отдельно от компонентов, чтобы всю логику приложения описывать в атомах.
В таком случае атомы можно легко тестировать без эмуляции DOM. А все компоненты становятся глупыми — их можно протестировать через Storybook.
ну почему же никто не читает про опыт который был уже в индустрии до того как вы пришли в нее!?? )
Был у нас MVC а затем и библиотеки типа Backbone когда в приложении были сотни таких атомов в иде моделей и коллекций. Это приводило к жути на проекте - куча непрозрачного кода для связи этих атомом между собой, направления потоков обновлений и их последовательность превращалась в хаос - это нигде явно не видно только руками по всему коду!!! В конце концов это приводило постоянно к зацикливаниям изменений для нахождения которых требовались адские усилия - брейкпоинты приходилось ставить по всему коду приложения
Вот почему индустрия сбежала от MVC во FLUX а затем доработали его в REDUX!
Если вам хочется понаступать на эти грабли - всегда пожалуйста :)
ну почему же никто не читает про опыт который был уже в индустрии до того как вы пришли в нее!?? )
Я в индустрии с 2004, Backone появился уже при мне, так что читать мне не нужно.
куча непрозрачного кода для связи этих атомом между собой, направления потоков обновлений и их последовательность превращалась в хаос
Обрати внимание, что я не говорил, что надо разбивать логику страницы на кучу разных атомов. У меня в приложении обычно логика страницы — это всего несколько относительно больших атомов в одном файле.
Мы же вроде говорили про другое — про вынос логики из компонента в стор. Логика не разбивается по кучи файлов (она вся оказывается в одной файле стора). Идея именно, что логика отдельно — HTML-шаблон отдельно.
нет не верно вы меня поняли!
я же написал в рекомендациях, что вопреки документации не нужно писать методы в стор - наоборот их лучше хранить отдельно, каждый метод в своем модуле - там он легче читается и тестируется
В сторе хранить нужно только структуры данных
вообще если говорить про логику, а это есть бизнес-логика = домен, то как минимум все доменные сущности должны быть в сторе домена и там же методы стора по изменению и управлению доменными сущностями, а в слое пользовательских сценариев уже должна располагаться логика приложения которая и должна вызываться на ваших страницах
Как же вы так код писали, что у вас постоянно возникали эти зацикливания?) Что-то мне подсказывает, что проблема-то была как раз не во фреймворке, а в кое чём другом.
И да, кстати, MobX изначально спроектирован так, что циклические зависимости там невозможны - код просто не запустится и явно подскажет вам где вы накосячили. Так что советую попробовать, возможно вы приятно удивитесь.)
как как? да все придурки до вас были - так и писали код. у всех руки были кривые все специально циклы писали - нравилось это всем! а как вы считаете? умные же все только сейчас в индустрию пришли а раньше одни криворукие были )
нет уж спасибо - меня Zustand своей простотой и гибкостью полностью удовлетворяет!
Я уже начинаю бояться любителей MobX - они все агрессивные токсичные и навязчивые! набежали написали фигни, нахамили, наставили минусов и постоянно уговаривают перейти на MobX как в секту ! Это просто уже подозрительно!
Не собираюсь я в такую секту вступать - я хочу остаться нормальным )
нет уж спасибо - меня Zustand своей простотой и гибкостью полностью удовлетворяет!
А скажите конкретно, в каком месте MobX сложнее чем Zustand? Я серьезно.
Например в MobX по факту в 95% используются лишь 2 функции:
1) makeAutoObservable(this)
в конструкторе класса
2) observer
в качестве враппера компонента
В остальных 5% в дополнении иногда применяют reaction, autorun и when, т.е. ещё 3 функции которые всё так же элементарные и узнать как они работают и для чего занимает около 5 минут.
Всё остальное время тупо нативный код, изменяешь переменные и вуаля. Только не надо говорить про магию и т.п., т.к. там всё супер просто ибо внутри getters/setters
Я уже начинаю бояться любителей MobX - они все агрессивные токсичные и навязчивые!
Скорее всего это просто нетерпимость к глупости)
перейти на MobX как в секту ! Это просто уже подозрительно!
Да, примкнуть к умным это верх идиотизма)))
Не собираюсь я в такую секту вступать - я хочу остаться нормальным )
Нормальный человек не будет использовать Zustand и тому подобную иммутабильную ерись которая не основана на getter/setters. Это всё равно что принципиально и преднамеренно не использовать интернет/сотовую связь и вместо этого общаться на расстоянии по средствам голубиной почты или писем. Или оплачивать квитанции на почте, а не сканировать QR код в приложении банка. Это ли не верх глупости)
сектанты секты свидетелей MobX - отcnаньте! Не вступлю я в вашу секту, где людей превращают в агрессивных, токсичных и навязчивых личностей!
Я в жизни не встречал таких негативно настроенных к другим людям сектантов! Ни разу не слышал наездов от любителей Recoil, Valtio, Restate и всех остальных стет-менеджеров.
Нормальные люди спокойно обсуждают технические особенности того или иного инструмента! Такое агрессивное негативное и токсичное поведение встретил только от свидетелей пришествия MobX!
Ужас! Чур меня, Чур!
Нормальные люди спокойно обсуждают технические особенности того или иного инструмента!
Так вы и ответьте нормально на комментарий, особенно на его первую часть. А не вот это вот всё.
Ужас! Чур меня, Чур!
Я понимаю что скорее всего вы не сможете ничего противопоставить, но хотя бы попытайтесь или признайте.
Помню, как спорил с Вами, но сейчас всё больше смотрю в сторону MobX.
Очередная статья про zustand, и снова тот же вопрос, зачем когда есть mobx?
Очередной вопрос про MobX - зачем MobX если есть Zustand?
Zustand проще, легче и гибче! :)
ну вот, допустим, компонент Counter
- он прибит гвоздями к хуку useCounterStore
Используя МобХ, я могу закидывать стор через пропсы:
interface ICounter {count: number, increment: VoidFunction;}
const Counter: FC<{store: ICounter}> = (...) => {...}
Или, например, вытащить стор из контекста. И т.д. Именно стор, при изменении данных внутри которого, будет ререндериться Counter, но не его родитель. В то же время передаваемый стор описывается простым и понятным интерфейсом.
В Зюстанде данная концепция как представлена?
Давайте по порядку
- если мы говорим о компоненте Счетчик - мы так же передаем в него данные через свойства, а хук у нас используется в контейнере - у нас чистая архитектура в проекте
- зачем контекст? контекст нам совсем не нужен в приложении!
- где у нас с Zustand сложный и не понятный интерфейс - у нас все просто и очень понятно!
- о какой концепции вы спрашиваете я так и не понял - напишите подробней
Попробуйте сформулировать вопрос в конструктивной форме а не в форме протеста и отрицания. Если вас интересует что и как реализовано в Zustand и почему он проще и быстрее - я готов с вами обсудить
Ок, если кратко: в компонент Counter
из моего примера можно передать любой объект, соответствующий интерфейсу ICounter
. Компонент не привязан к одному стору. Из вашей статьи я понял (возможно, ошибочно), что за хуком useCounterStore
(и, как следствие, за компонентом, его использующим) закреплен один конкретный стор, и что делать, если нужно несколько каунтеров, не совсем ясно.
я понял вопрос
смотрите у нас, как я и написал ниже в рекомендация, все связанные структуры данных хранятся в одном сторе, поэтому когда вы вызываете хук `useAppStore` вы получаете доступ ко всем структурам в сторе
В вашем случае несколько каунтеров были бы в одном сторе
Ваш вопрос раскрывает проблемы многосторных приложений - когда их становится много - ими становится сложно управлять, их везде нужно таскать толпой, логика связей размазана по коду, изменения в одном сторе могут приводить к изменениям в другом сторе и так далее по цепочке и как часто это было ив MVC и во фреймворках типа Backbone (где были сотни таких сторов в виде моделей) это всегда приводило к зацикливанию изменений найти которое было еще тем адским трудом
Если я не ответил на ваш вопрос - уточните я попробую объяснить
Как в итоге будет выглядеть компонент Counter, если возможных каунтеров несколько?
const UseAppStore = create(() =>{
catsCounter : 0,
dogsCounter: 0,
....
})
function Counter(){
// const catsCounter = UseAppStore(state => state.catsCounter)
const dogsCounter = UseAppStore(state => state.dogsCounter)
...
}
я правильно понял задачу что нужно выбрать один из каунтеров?
Задача: написать компонент Counter, который можно легко пристыковать к любому подходящему стору.
Иллюстрация на mobx (не ради холивара, а только в иллюстративных целях!):
interface ICounter {
count: number;
increment: VoidFunction;
}
const Counter: FC<{store: ICounter}> = observer(({store}) => {
return <button onClick={store.increment}>{store.count}</button>;
}
Получился компонент с явно заданными зависимостями. К нему очень легко написать тесты - достаточно впендюрить заглушку
const stub = {
count: 0,
increment: jest.fn(),
};
С архитектурной точки зрения компонент хорош тем, что ничего не знает о проектных особенностях, и может быть переиспользован в различных ситуациях. Он лишь задает требуемый интерфейс, и ничего больше.
Ваш набросок кода предполагает, что Counter фактически завязан на некий "каталог всех возможных каунтеров", что менее гибко.
у нас тоже все по феншуюfunction Counter({count, increment}: {count: number, increment: ()=>void}) {
return <button onClick={store.increment}>{store.count}</button>;;
}
function CounterContainer() {
const { count, increment} = useAppStore(state=> state.counter)
return <Counter count={count} increment={increment}>;
}
по поводу способа передачи параметров одним объектом или несколькими свойствами - это уже на вкус
как можете видеть никаких проблем с тестированием
но на самом деле - это наивная реализация - у нас слоеная архитектура и в контейнерах мы вызываем уже не стор а юзкейсы
я правда не понял ваш вопрос про концепции
сформулируйте его более понятно и я смогу конструктивно ответить
Проще mobx ничего нет, обычный жс и makeAutoObservable и observer, и все работает и оптимизировано из коробки
Забейте, на Хабре культ MobX головного мозга, буквально под каждым постом они. Они ничего другого просто не воспринимают.
Смотрю я последнее время на хабр и становится грустно от огромного количества статей на тему этих zustand, effector и прочих.
Грустно от того, что люди не понимают, что все эти стейт менеджеры представляют из себя синглтоны, склоняют к использованию синглтонов, никак не решают проблемы взаимосвязей разных сущностей и по факту совершенно не заботятся о производительности.
И в этой статье также одни розовые сопли и никакой аналитики, сравнений с нормальными решениями типа MobX, чуть более сложных примеров, чем банальный каунтер, примеров масштабирования системы, её гибкости.
И этот момент:
Создание отдельных хранилищь оправдано лишь для:
реально не зависимых структур данных
для данных в микрофронтах
Ну уж извините. Создание отдельных хранилищ оправдано огромным количеством различных причин. К примеру:
Декомпозиция бизнес логики на составляющие и её инкапсуляция
Повышение реиспользуемости разных частей приложения
Увеличение связность и уменьшение зацепления (а в общих сторах вся всегда очень зацеплено и слабо связано)
Code Splitting
Поддерживаемость
Производительность
Конеш удобненько хранить всё своё состояние в одном огромном дереве. Удобно, когда у тебя две формочки на весь проект и одна единственная корзина с товарами. А когда корзин становится две, то уже возникают сложности.
Эх, вот использовал бы народ MobX повсеместно, глядишь фронтендеров и за людей бы начали считать...
И в этой статье также одни розовые сопли и никакой аналитики, сравнений с нормальными решениями типа MobX, чуть более сложных примеров, чем банальный каунтер, примеров масштабирования системы, её гибкости.
Извините, но после таких фраз обсуждать нечего да и не хочется особо
Такие безапелляционные заявления - это верх пренебрежения, боязнь нового и попахивает не компетентностью
У нас большое приложение больше 2х лет работы и ни одного каунтера - сплошь сложные структуры данных и сложная логика.
В общем после таких заявлений - одни негативные эмоции возникают (
> Декомпозиция бизнес логики на составляющие и её инкапсуляция
ваша "декомпозиция" приводит к композиции сложности и не надежности приложения (об этом написано в статье) - попробуйте в базах данных кому-нибудь рассказать что вы хотите часть базы данных "декомпозировать" - вас сразу же "декомпозируют" подальше от нее.
> Повышение реиспользуемости разных частей приложения
вот тут просто набор слов - не понятно как на него реагировать
> Увеличение связность и уменьшение зацепления (а в общих сторах вся всегда очень
зацеплено и слабо связано)
вообще мимо - это относится к коду но не к данным
> Code Splitting
не нужно путать код сплиттинг с разбиением данных на хранилища - это вещи абсолютно разного порядка. Асинхронно загружаемых бандлов может быть сколько угодно, но какое отношение они имеют к хранилищу данных, к целостности и не противоречивости их??
> Поддерживаемость
вот как раз поддерживаемость одного хранилища в разы выше чем кучи хранилищ с непрозрачной логикой связи, с разнонаправленными потоками обновления данных и тд и тп - еще раз повторюсь в статье этот кейс описан
> Производительность
о какой производительности вы ведете речь - пожалуйста код в студию с измерениями!
Такое ощущение что вы боитесь потерять работу потому что ваш MobX задвинут и возьмут в работу что-то более простое, легкое и гибкое
В общем не пишите пожалуйста больше в таком пренебрежительном стиле и тональности - вы вызываете такими комментами только негативные эмоции.
Если вас интересуют технические аспекты - задавайте вопросы - я готов обсуждать
вообще мимо - это относится к коду но не к данным
И к данным тоже, если вам ближе сторона RDM в дискуссии "RDM vs. ADM". В лучших практиках из вашей статьи п.3 явно в пользу RDM.
Такие безапелляционные заявления - это верх пренебрежения, боязнь нового и попахивает не компетентностью
Замечу, что я на личности таки не переходил, а вы почему-то сразу решили это сделать. Видимо, почувствовали свою несостоятельность.)
Боязни нового тут нет. Просто есть проверенное временем решение, лучше которого, к сожалению, пока ничего не придумали. А вот это ваше неудержимое джуниорское желание попробовать всё новое и запихать в проект все возможные хайпующие технологии до добра обычно не доводит (сам таким был, каюсь, и спустя много лет понимаю какую свинью подложил той компании, где я такое практиковал) и приходится после этого приходить на проект и выкорчёвывать целый зоопарк сомнительных решений.
У нас большое приложение больше 2х лет работы и ни одного каунтера - сплошь сложные структуры данных и сложная логика.
А что ж тогда в статье об одном лишь каунтере рассказали? Привели бы в пример кейсы, где zustand реально хорошо себя показывает, тогда вопросов бы не было. Пока же в статье показаны кейсы, где MobX показывает себя гораздо лучше.
ваша "декомпозиция" приводит к композиции сложности и не надежности приложения (об этом написано в статье) - попробуйте в базах данных кому-нибудь рассказать что вы хотите часть базы данных "декомпозировать" - вас сразу же "декомпозируют" подальше от нее.
Если честно, вы такими заявлениями дискредитируете себя ещё больше.)
Ну, если вы рекомендуете своим коллегам строить огромных колоссов на глиняных ногах, то мне вас откровенно жаль и ещё больше жаль ваших коллег, которые будут работать с этим и поддерживать эти бесконечно большие модели, пытаясь к ним прицепить новую функциональность, при этом не поломав всё остальное.
БД в качестве примера приводить не стоит, всё же это совершенно сторонняя концепция и она мало чем связана непосредственно с бизнес логикой приложений. И на самом-то деле даже БД уже спокойно себе декомпозируют и разбивают на независимые суб бд для микросервисов. Но, повторюсь, к делу это никакого отношения не имеет. Бизнес логика приложений строится совершенно по другим принципам.
И думаю стоит сказать о простых человеческих возможностях - работать с одной огромной сущностью с внутренними взаимосвязями гораздо сложнее, чем с набором малых, которые взаимодействуют между собой. Малые сущности позволяют абстрагировать как логику, так и данные и оперировать бОльшими блоками, что очень удобно для нашего мозга - не нужно погружаться в детали реализации, можно просто использовать интерфейсы. Если же у вас одно огромное хранилище, то придется держать в голове кучу взаимосвязей внутри него, знать о каждой его части и что на неё может воздействовать.
Могу предположить, что у вас просто не получалось наладить взаимодействие этих отдельных блоков и они превращались в один плотно скрученный пучок отношений (слабая связность, сильное зацепление). Для решения таких проблем существует большое количество разных паттернов, которые позволят вам достичь гораздо лучшего результата. Почитайте туже банду 4, к примеру. Ну или хотя бы пройдитесь по статье на вики. Думаю после этого вам станет более понятно, как организовать ваш код таким образом, что б не приходилось решать ваши проблемы с помощью объединения всего и вся в одну мега сущность.
вот тут просто набор слов - не понятно как на него реагировать
Да, я догадывался, что для вас это будет просто набором слов, но надеялся что всё же поймёте.
вообще мимо - это относится к коду но не к данным
Ага, а данные у нас в коде конечно же никак не представлены.
не нужно путать код сплиттинг с разбиением данных на хранилища - это вещи абсолютно разного порядка. Асинхронно загружаемых бандлов может быть сколько угодно, но какое отношение они имеют к хранилищу данных, к целостности и не противоречивости их??
А вот из-за таких домыслов производительность современного фронтенда и находится в жопе. Т.к. многие думают что достаточно кодсплитить одни вьюхи, а всю логику поставлять в одном единственном чанке на всё приложение (привет редакс). Да, конечно есть воркераунды для этого дела, но не только лишь все ими пользуются...
А если же всё же декомпозировать ваш этот огромный стор на составляющие и разместить рядом с ними связанную логику и представления, то можно с лёгкостью разделить приложение на независимые части и поставлять их пользователю по запросу (при SPA переходе, открытии модалки и т.д.). Это уменьшит вес вашего основного чанка, ускорит его парсинг и выполнение.
вот как раз поддерживаемость одного хранилища в разы выше чем кучи хранилищ с непрозрачной логикой связи, с разнонаправленными потоками обновления данных и тд и тп - еще раз повторюсь в статье этот кейс описан
Поздравляю, вы противоречите официальной доке zustand.)
Ну и выше я постарался объяснить с помощью базовых принципов человеческого мышления почему это важно.
о какой производительности вы ведете речь - пожалуйста код в студию с измерениями!
Слушайте, вам бы самому в начале стоит код привести, графики, сравнения, а не бравировать пустыми домыслами об этой самой производительности у zustand.
Производительность же раздельных сторов базируется на простом принципе - иммутабельно изменять огромное дерево в любом случае будет менее производительным, чем изменение независимых сторов и обновление только тех представлений, которые этого требуют.
Такое ощущение что вы боитесь потерять работу потому что ваш MobX задвинут и возьмут в работу что-то более простое, легкое и гибкое
MobX не задвинут ни разу, вы очень сильно ошибаетесь. Он простой, легкий и очень, нет, ОЧЕНЬ гибкий. Возможно даже излишне гибкий и из-за этого такие как вы просто боитесь его использовать, т.к. вам проще идти на поводу у решений, которые банально не дают вам возможности сделать шаг в сторону, подумать о том, а какой же паттерн тут лучше применить, подумать о том, как сделать код более масштабируемым, поддерживаемым, гибким. И решением всех ваших проблем становится один лишь pubsub. О да, самый лучший паттерн.)
И да, вы очень сильно удивитесь какие по масштабу проекты пилят именно на MobX.
Мда, это тяжелый случай... Как бы вот уже с 2016 году есть решение. Коню же понятно что лучше решений основанных на getters/setters просто нет и быть не может.
Раз
Два
Три
https://stackblitz.com/edit/stackblitz-starters-gsc7kl?file=src%2FApp.tsx
Имею опыт 2-х лет на MobX, сейчас использую Zustand около 2-х месяцев. Я думал MobX никто не переплюнет, но Zustand показался удобнее и проще. Мне единственно не получается его оптимизировать по размеру бандла. Я использую Zustand одновременно и с React и без - для браузерного расширения. Так вот чтобы его использовать без реакта внутри всё равно подтягивается зависимость: zustand -> use-sync-external-store/shim -> react
кто подскажет как убрать эту зависимость?
рад, что попробовали и то и другое и можете объективно оценить!
( только переживаю за вас - сейчас свидетели MobX налетят на вас толпой и будут хэйтить и минусовать ? )
задайте вопрос в разделе Дискуссии проекта - Дайши Като (маинтейнер) общительный парень и оперативно отвечает на все вопросы
свидетели MobX налетят на вас толпой и будут хэйтить...
...за невнимательное чтение документации. Устав нашей секты такое не приветствует!
https://www.npmjs.com/package/zustand#using-zustand-without-react
но Zustand показался удобнее и проще
А скажите конкретно, в каком месте MobX сложнее/не удобнее чем Zustand? Я серьезно.
Например в MobX по факту в 95% используются лишь 2 функции:
1) makeAutoObservable(this)
в конструкторе класса
2) observer
в качестве враппера компонента
В остальных 5% в дополнении иногда применяют reaction, autorun и when, т.е. ещё 3 функции которые всё так же элементарные и узнать как они работают и для чего занимает около 5 минут.
Всё остальное время тупо нативный код, изменяешь переменные и вуаля. Только не надо говорить про магию и т.п., т.к. там всё супер просто ибо внутри getters/setters
Я пользовался MobX в 2019-2021. 2 полных года коммерческой разработки - делали на нём и интернет магазины и веб/мобильный-банкинг довольно большие SPA.
Я не в курсе как сейчас, но сравниваю тогдашний MobX с теперешним Zustand.
В MobX нужно было дополнительно описывать state tree дополнительным пакетом, в Zustand это из коробки. TypeScript из коробки.
Потом парсер на MobX постоянно пропускал данные и ругался. Например бекендер невнимательно сделал и возвращал undefined вместо null, а в MobX я должнен явно указывать это. В итоге я постоянно бегал в модели и правил null на возможный undefined или на пустую строку, которая еще и может быть null.
Иногда пропускал обернуть в observable компонент или пробросить из состояния, в Zustand для меня нагляднее.
Вызов родительской модели из дочерней создавал неудобство.
Асинхронные экшены тоже тогда через звездочку описывались через генераторы.
.В MobX нужно было дополнительно описывать state tree дополнительным пакетом
С чего это вдруг "В MobX нужно было дополнительно описывать state tree"?? Если вы жесткий извращенец, то да, такие люди зачем-то используют mobx-state-tree. Но это сугубо говорит о умственных способностях этих людей, а не о том, что mobx плохой. Вот mobx-state-tree плохой, это да, я бы сказал даже убогий.
Потом парсер на MobX постоянно пропускал данные и ругался. Например бекендер невнимательно сделал и возвращал undefined вместо null, а в MobX я должнен явно указывать это.
Это опять относится чисто с mobx-state-tree, а не к mobx. Да тут я с вами согласен, mst это полное дно)
Иногда пропускал обернуть в observable компонент
Это сугубо ваша проблема и вашей невнимательности и т.п., никак к mobx не относится) Тем более никто не запрещает написать плагин к webpack или vite чтобы компоненты автоматически заворачивались в observer, и вам даже не надо было на это тратить лишнюю секунду) У меня например уже давно такой плагин написан и не только)
Вызов родительской модели из дочерней создавал неудобство.
Каким образом? Наверное вы просто не знали как это делать, разные варианты есть же.
Асинхронные экшены тоже тогда через звездочку описывались через генераторы.
Это тоже от незнания, увидели вредный пример в доке и бездумно используете) Вообще не так так делать, просто пишите async () => {...} без всяких экешенов и т.п. А для автобатчинга можно легко сконфигурировать mobx.
Вот:
import { configure } from 'mobx';
let reactionSchedulerTimeout = null;
// When we need synchronous reactions change this to true, example for input/textarea
export const mobxSyncReaction = {
__val: false,
__nextVal: false,
set value(v) {
if (v === true) {
this.__val = v;
this.__nextVal = v;
} else {
this.__nextVal = false;
}
},
get value() {
return this.__val;
},
};
// Configure MobX to auto batch all sync mutations without using action/runInAction
setTimeout(() => {
configure({
enforceActions: 'never',
reactionScheduler: (f) => {
if (mobxSyncReaction.value) {
f();
mobxSyncReaction.__val = mobxSyncReaction.__nextVal;
} else {
clearTimeout(reactionSchedulerTimeout);
reactionSchedulerTimeout = setTimeout(f);
}
},
});
}, 1);
И всё, после этого тупо нативный код пишите и не парьтесь, никаких action'ов не нужно.
Вот смотрите какая красота:
https://stackblitz.com/edit/stackblitz-starters-m2hsxf?file=src%2FApp.tsx
И только 1 рендер, т.к. автобатчинг.
И пример когда мы хотим синхронные реакции включить:
привет!
встроенные методы не приветствую и не использую (см п.3 рекомендации) но в коде за api скрывается интерфейс pub/sub объекта (реального хранилища данных)
interface StoreApi<T> {
setState: SetStateInternal<T>;
getState: () => T;
getInitialState: () => T;
subscribe: (listener: (state: T, prevState: T) => void) => () => void;
}
эти методы пробрасываются для прямых подписок и прямых манипуляций с данными в хранилище (когда внутри метода хранилища какие-то объекты могут подписываться на обновление данных и реагировать) - думаю что это для крайне экзотических ситуаций и в 99 .9% случаев он не используется - достаточно предоставляемых методов get и set
методы get и set - просто синонимы методов getState
и setState
пример с set есть либо в readme либо в доке - точно помню
в статью, я думаю не нужно включать, статья получится копией документации - смысл статьи показать основные возможности и заинтересовать, а детали уже всегда можно в доке найти
Zustand.js: современный, невесомый, производительный и очень гибкий state manager