패키지, 저장소 및 앱 카테고리 검색

패키지 상세v1.0.2

june

June는 Flutter의 네이티브 상태 관리와 매우 유사한 패턴을 제공하는 가볍고 현대적인 상태 관리 라이브러리입니다.

AndroidiOSWebmacOSWindowsLinux
30일 다운로드
173
좋아요
88
Pub 점수
150

패키지 설치

flutter pub add june

패키지 개요

공개 정보를 바탕으로 생성한 선택 가이드입니다.

June는 Flutter의 네이티브 상태 관리 패턴을 모방하는 가볍고 현대적인 상태 관리 라이브러리입니다. 단순성과 가독성을 중시하여 봐야 할 코드 없이 반응형 방식으로 상태를 쉽게 관리할 수 있습니다. 개발자 경험을 최우선으로 고려해 설계되었으며, 기존의 Flutter 프로젝트에 원활하게 통합 가능하고 모든 주요 플랫폼을 지원합니다. 그 API는 직관적이며 깔끔한 코드 구조와 효율적인 업데이트를 촉진합니다. June는 더 복잡한 상태 솔루션 대안으로서 최소한의 강력한 선택지를 찾는 개발자에게 이상적입니다.

사용 사례

  • 간단한 앱 상태 관리
  • 반응형 UI 업데이트
  • 크로스 플랫폼 플러터 앱
  • 경량 상태 솔루션
  • 기존 코드베이스와의 간편한 통합

주요 기능

  • 최소한의 보일러플레이트
  • Flutter-네이티브 패턴 정렬
  • 반응형 상태 업데이트
  • Platform-agnostic
  • 깔끔하고 읽기 쉬운 API
  • 외부 종속성 없음

적합한 대상

  • 초보자에서 중급자까지의 Flutter 개발자
  • 소규모에서 중규모 애플리케이션
  • 간결함을 우선시하는 프로젝트
  • 빠른 온보딩을 원하는 팀
  • 다중 플랫폼을 대상으로 하는 앱

고려 사항

  • 더 큰 라이브러리와 비교해 고급 기능이 제한됨
  • 매우 대규모 규모의 상태 요구에 적합하지 않음
  • 성숙한 대안보다 커뮤니티 지원이 적음
  • 간단한 상태 흐름에 가장 적합

원본 README

연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.


     ██╗██╗   ██╗███╗   ██╗███████╗
     ██║██║   ██║████╗  ██║██╔════╝
     ██║██║   ██║██╔██╗ ██║█████╗
██   ██║██║   ██║██║╚██╗██║██╔══╝
╚█████╔╝╚██████╔╝██║ ╚████║███████╗
 ╚════╝  ╚═════╝ ╚═╝  ╚═══╝╚══════╝
Flutter state management that feels like Flutter.

Pub Version Pub Likes Pub Points GitHub Stars

Discord KakaoTalk Docs



The problem with state management today

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 _CounterState extends State<Counter> {
  int count = 0;         // 🔒 only this widget
                         //    can touch this

  @override
  Widget build(BuildContext context) {
    return Text('$count');
  }
}

With June — state lives anywhere, rebuilds anything

class CounterVM extends JuneState {
  int count = 0;         // ✅ any widget,
                         //    any file,
}                        //    anywhere
JuneBuilder(
  () => CounterVM(),
  builder: (vm) => Text('${vm.count}'),
)


Why June wins on simplicity

June Provider GetX Bloc
No MaterialApp wrapper needed ✅ ❌ ❌ ❌
No manual initialization ✅ ❌ ✅ ❌
Works with StatelessWidget ✅ ✅ ✅ ✅
Call setState from anywhere ✅ ❌ ✅ ❌
Multiple tagged instances ✅ ❌ ✅ ❌
Per-widget isolated state ✅ ❌ ❌ ❌
Zero new architecture required ✅ ❌ ❌ ❌


Installation

dependencies:
  june: ^1.0.2
flutter pub get


Quick start — 3 steps, 3 minutes

Step 1 — Define your state
class CounterVM extends JuneState {
  int count = 0;
}
Step 2 — Subscribe a widget
JuneBuilder(
  () => CounterVM(),
  builder: (vm) => Text('${vm.count}'),
)
Step 3 — Update from anywhere
June.getState(() => CounterVM())
  ..count++
  ..setState();

No providers. No streams. No boilerplate. setState works the same way it always has — just across the whole app.



Full runnable example

import 'package:flutter/material.dart';
import 'package:june/june.dart';

void main() => runApp(const MyApp());

// ─── State ─────────────────────────────────────────────────────────────────

class CounterVM extends JuneState {
  int count = 0;

  void increment() {
    count++;
    setState();
  }
}

// ─── UI ────────────────────────────────────────────────────────────────────

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: JuneBuilder(
            () => CounterVM(),
            builder: (vm) => Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                const Text('You have pushed the button this many times:'),
                Text(
                  '${vm.count}',
                  style: Theme.of(context).textTheme.headlineMedium,
                ),
              ],
            ),
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => June.getState(() => CounterVM()).increment(),
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}


Patterns

Methods on state

Keep logic next to data. Call it from anywhere.

class CounterVM extends JuneState {
  int count = 0;

  void increment() {
    count++;
    setState();
  }

  void reset() {
    count = 0;
    setState();
  }
}
// From a button, a gesture, a timer — anywhere
June.getState(() => CounterVM()).increment();

Multiple instances with tag

One state class, many independent instances — perfect for list items, cards, feeds.

JuneBuilder(
  () => CounterVM(),
  builder: (vm) => Text('Default: ${vm.count}'),
)

JuneBuilder(
  () => CounterVM(),
  tag: 'card_a',
  builder: (vm) => Text('Card A: ${vm.count}'),
)

JuneBuilder(
  () => CounterVM(),
  tag: 'card_b',
  builder: (vm) => Text('Card B: ${vm.count}'),
)
// Update only card A — other instances are unaffected
June.getState(() => CounterVM(), tag: 'card_a')
  ..count++
  ..setState();

Per-widget local state with global: false

For state that belongs to exactly one widget — not shared globally. Pass your own instance and June won't register it.

class SliderState extends JuneState {
  double value = 0.5;
}
final sliderState = SliderState();

JuneBuilder(
  () => sliderState,
  global: false,
  builder: (s) => Slider(
    value: s.value,
    onChanged: (v) {
      s.value = v;
      s.setState();
    },
  ),
)

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.

class ThemeController extends JuneState {
  bool isDark = false;

  void toggle() {
    isDark = !isDark;
    setState();
  }
}
return JuneBuilder(
  () => ThemeController(),
  builder: (c) => MaterialApp(
    theme: ThemeData.light(),
    darkTheme: ThemeData.dark(),
    themeMode: c.isDark ? ThemeMode.dark : ThemeMode.light,
    home: const HomeScreen(),
  ),
);

Async state / HTTP

Call setState() when your data arrives. Works with any Future or Stream.

class UserController extends JuneState {
  User? user;
  bool loading = false;

  Future<void> loadUser(String id) async {
    loading = true;
    setState();

    user = await userRepository.fetch(id);
    loading = false;
    setState();
  }
}
JuneBuilder(
  () => UserController(),
  builder: (c) {
    if (c.loading) return const CircularProgressIndicator();
    if (c.user == null) return const Text('No user loaded');
    return Text('Hello, ${c.user!.name}');
  },
)

Selective rebuilds with id

Trigger only specific JuneBuilder widgets inside a shared state, leaving others untouched.

class FeedState extends JuneState {
  String header = 'Latest';
  List<Post> posts = [];

  void updateHeader(String value) {
    header = value;
    setState('header');          // only rebuilds builders with id: 'header'
  }

  void refreshPosts(List<Post> fresh) {
    posts = fresh;
    setState('posts');           // only rebuilds builders with id: 'posts'
  }
}
// Rebuilds only when 'header' setState is called
JuneBuilder(
  () => FeedState(),
  id: 'header',
  builder: (s) => Text(s.header),
)

// Rebuilds only when 'posts' setState is called
JuneBuilder(
  () => 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?

Discord KakaoTalk Docs



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.


Made with care for the Flutter community.

카테고리

소스 저장소

이 패키지를 사용하는 프로젝트

아직 데이터가 없습니다.