June は、Flutter のネイティブな状態管理パターンを模倣する軽量で現代的な状態管理ライブラリです。シンプルさと読みやすさを重視しており、ボイラープレートなしにリアクティブに状態を管理しやすくしています。開発者の体験を最優先に設計されており、既存の Flutter プロジェクトにスムーズに統合でき、すべての主要プラットフォームをサポートしています。その API は直感的で、クリーンなコード構造と効率的な更新を促進します。June は、より複雑な状態管理ソリューションの代替として、最小限ながら強力な選択肢を探している開発者に最適です。
You learned Flutter. You learned setState. It clicked.
Then you added a library and suddenly you're learning a new framework inside your framework — providers, stores, atoms, streams, reducers.
June refuses to do that.
It gives you shared, reactive state that works exactly like Flutter's own state management — just without the widget tree dependency. That's it.
At a glance
Before June — state trapped in a widget
class_CounterStateextendsState<Counter> {
int count = 0; // 🔒 only this widget// can touch this@overrideWidgetbuild(BuildContext context) {
returnText('$count');
}
}
With June — state lives anywhere, rebuilds anything
classCounterVMextendsJuneState{
int count = 0; // ✅ any widget,// any file,
} // anywhere
Each widget holds its own isolated state. Navigating away and back creates a fresh instance — exactly what you want for forms, sliders, and single-use UI.
Theme toggle
JuneBuilder can wrap MaterialApp itself, rebuilding the entire app on state change.
JuneBuilder(
() => UserController(),
builder: (c) {
if (c.loading) returnconstCircularProgressIndicator();
if (c.user == null) returnconstText('No user loaded');
returnText('Hello, ${c.user!.name}');
},
)
Selective rebuilds with id
Trigger only specific JuneBuilder widgets inside a shared state, leaving others untouched.
classFeedStateextendsJuneState{
String header = 'Latest';
List<Post> posts = [];
voidupdateHeader(String value) {
header = value;
setState('header'); // only rebuilds builders with id: 'header'
}
voidrefreshPosts(List<Post> fresh) {
posts = fresh;
setState('posts'); // only rebuilds builders with id: 'posts'
}
}
// Rebuilds only when 'header' setState is calledJuneBuilder(
() => FeedState(),
id: 'header',
builder: (s) => Text(s.header),
)
// Rebuilds only when 'posts' setState is calledJuneBuilder(
() => FeedState(),
id: 'posts',
builder: (s) => PostList(posts: s.posts),
)
Core API
Symbol
Role
JuneState
Base class for all state objects. Extend it, add fields and methods, call setState() to rebuild.
JuneBuilder
Widget that subscribes to a JuneState and rebuilds when setState() fires.
June.getState()
Retrieves (or lazily creates) a global singleton of a state type. Thread-safe, no setup needed.
tag
Namespaces multiple global instances of the same type.
id
Enables partial rebuilds — only JuneBuilder widgets sharing the same id will rebuild.
global: false
Bypasses the global registry. The builder uses your provided instance directly.
tag vs id — when to use which
tag
id
Lives on
JuneBuilder & June.getState()
JuneBuilder & setState()
Purpose
Pick which stored instance to use
Pick which builders to rebuild
Use when
Same state type needed in multiple places independently
One shared state, but only some widgets should react to a given change
Migration
0.8.x → 1.0.0
The factory function is now passed as a closure rather than an evaluated instance:
// Before (0.8.x)June.getState(CounterVM());
// After (1.0.0+)June.getState(() => CounterVM());
Community
Questions, ideas, or just want to say hi?
Acknowledgements
June was shaped by the best ideas in the Flutter ecosystem. Gratitude to the teams and communities behind Provider, GetX, Bloc, and Riverpod, and to Svelte for proving that less really is more.