Изменено: 02.06.2026
В shared-слое используется FlowMVI. UI отправляет события в Kotlin-компоненты, а компоненты уже передают их в store/container.
Хороший пример - TransactionsComponent. В нём видно основной контракт:
TransactionsState- состояние экранаTransactionsIntent- событие от UITransactionsAction- одноразовое действиеTransactionsContainer- контейнер с логикой обработкиStore<TransactionsState, TransactionsIntent, TransactionsAction>- FlowMVI store
React UI
-> component.intent(...)
-> FlowMVI container
-> UseCase
-> Repository
-> State update
-> jsState subscription
-> React render
React не должен напрямую вызывать репозитории. Его задача - отправить intent и подписаться на состояние.
State хранит то, что нужно экрану для отрисовки. Actions подходят для одноразовых событий: навигации, toast-сообщений и похожих эффектов.
Эти вещи лучше не смешивать. Если одноразовое событие положить в persistent state, UI может обработать его повторно после пересоздания компонента.
Компоненты, которые вызываются из TypeScript, используют @JsExport и обёртки из utils:
JsValue<T>JsChildSlot<T>jsStateSubscribe(...)subscribeActions(...)
Через это React получает текущее состояние, подписывается на изменения и отправляет intents обратно в Kotlin.
Новый экран стоит строить по тому же принципу:
- описать State, Intent и Action;
- вынести бизнес-операции в use case'ы;
- собрать FlowMVI container;
- экспортировать компонент в JS только через понятный API;
- не давать React доступ к репозиториям напрямую.