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.