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

패키지 상세v0.0.5

sprinkle

편리한 스트림 기반의 Flutter 아키텍처

30일 다운로드
15
좋아요
17
Pub 점수
10

패키지 설치

flutter pub add sprinkle

패키지 개요

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

Sprinkle은 단순성과 확장성을 목표로 한 스트림 기반의 Flutter 아키텍처입니다. 스트림을 통해 반응형 프로그래밍을 활용하여 상태와 종속성을 관리하고 앱 전체에서 효율적인 데이터 흐름을 가능하게 합니다. 명확한 관심사 분리로 비즈니스 로직을 UI 컴포넌트로부터 분리함으로써 테스트 가능성과 유지보수성을 높입니다. Flutter 위젯 트리와 원활하게 통합되며 의존성 주입을 지원하므로 중소 규모부터 대규모 애플리케이션에 적합합니다. 최소한의 보일러플레이트와 직관적인 패턴을 통해 개발자 경험을 강조합니다.

사용 사례

  • 반응형 UI 업데이트
  • 복잡한 앱에서의 상태 관리
  • Flutter에서의 의존성 주입
  • 스트림 기반의 데이터 흐름
  • 테스트 및 디버깅 워크플로우

주요 기능

  • 스트림 기반 상태 관리
  • 내장된 종속성 주입
  • 최소한의 보일러플레이트
  • 테스트 가능한 아키텍처
  • 관심사의 명확한 분리

적합한 대상

  • 중대형 플러터 프로젝트
  • 반응형 패턴을 찾는 개발자
  • 유지보수성을 우선시하는 팀
  • 확장 가능한 상태 솔루션이 필요한 앱
  • 테스트 가능성에 중점을 둔 프로젝트

고려 사항

  • 스트림에 대한 이해가 필요합니다
  • 초보자를 위한 학습 곡선
  • 다른 대안들에 비해 문서가 제한적
  • 매우 간단한 앱에는 적합하지 않음
  • 고급 기능을 사용하려면 추가 설정이 필요할 수 있습니다

원본 README

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

sprinkle

A convenient Flutter architecture for happy programmers

Getting Started

Overview

State Management

Sprinkle is based on streams. Streams are one of the core mechanics in Dart and in Flutter. Whether you are interacting with your database (e.g. Firebase) or trying to control the order and timing of requests sent to an API, streams are the most natural solution for these scenarios - we could say that streams are idiomatic in Flutter.

Why don't we use streams everywhere for simplicity and coherence then?! Streams are considered difficult, but that reputation is slightly exaggerated. Once you understand the benefits, there is no coming back to traditional state management approaches. And Sprinkle simplifies stream complexities - it's an easy to understand and coherent solution for state management in Flutter.

Reactive

Start by creating a Manager. It's a class that manages one or many data stores. It also exposes actions as methods to change the state in these data stores.

class CounterManager extends Manager {
  // 1. we create a data store (it's just a stream underneath)
  // Managers are immutable, thus stores must be `final`
  final counter = 0.reactive

  // 2. we define some actions
  void increment() => counter.value++;
  void decrement() => counter.value--;
  void add(int number) => counter.value += number;
}

Somewhere in the widget tree, inside the build method we can ask for a specific Manager by using the use method of the BuildContext

class Counter extends StatelessWidget { // Our widgets are *always* stateless
  @override
  Widget build(BuildContext context) {
    // 3. we include a manager with `use`
    var manager = context.use<CounterManager>();

    return Center(
      // 4. we observe a part of widget tree
      child: Observer<int>(
        // 5. we listen to a specific stream from the manager
        stream: manager.counter,
        // 6. we rebuild once the stream changes
        builder: (context, value) => Text("Counter: $value"),
      ),
    );
  }
}

Reactivity is enabled for the following types in Dart:

bool
final value = false.reactive;
int
final value = 42.reactive;
String
final value = 'The quick brown fox jumps over the lazy dog'.reactive;
List
final value = <String>[].reactive
Automatic Provider Setup

Use the Sprinkle widget to split the responsibilities and reduce the boilerplate so that you can write this:

final supervisor = Supervisor()
  .register<AManager>(() => AManager())

void main() => runApp(Sprinkle(supervisor: supervisor, child: App()));

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      ...
    )
  }
}

instead of this:

void main() => runApp(EmailApp());

class EmailApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Provider(
      data: Supervisor()
          .register<AManager>(() => AManager())
      child: MaterialApp(
        ...
      ),
    );
  }
}

Manager asks another Manager for help

In this example LoginManager asks for AuthManager. This goes through Supervisor and the requested manager is either provided as-is or instantiated.

class LoginManager extends Manager {
   void logout() {
     var manager = use<AuthManager>()

     manager.setAuthState(AuthState.loggedOut);
   }

   @override
   void dispose() {}
 }
Convenience Methods

Some convenience methods that follow the Pareto principle, i.e. Sprinkle makes aliases for the most common code scenarios.

Navigation

To change routes, you can write

context.display(AnotherPage())

instead of

Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => AnotherPage()),
);
SnackBar

To display a snackbar, you can write:

context.showSnackBar("...you text");

instead of

Scaffold.of(context).showSnackBar(
  SnackBar(content: Text('Yay! A SnackBar!'))
);
mediaQuerySize

to get MediaQuery Size, you can write:

context.mediaQuerySize

instead of


MediaQuery.of(context).size

orientation

to get Device orientation, you can write:

context.orientation

instead of


MediaQuery.of(context).orientation

isLandscape

to check if Device orientation is Landscape, you can write:

context.isLandscape

instead of


MediaQuery.of(context).orientation == Orientation.landscape

isPortrait

to check if Device orientation is Portrait, you can write:

context.isPortrait

instead of


MediaQuery.of(context).orientation == Orientation.portrait

Padding

Use .padding() method on widgets directly

Column(
  children: [
    Text("User 1").padding(8),
    Text("User 2").padding(8),
  ],
);

instead of wrapping them with Padding:

Column(
  children: [
    Padding(
      padding: EdgeInsets.all(8.0),
      child: Text("User 1"),
    ),
    Padding(
      padding: EdgeInsets.all(8.0),
      child: Text("User 2"),
    ),
  ],
);
Center

Use .center() method on widgets directly

Column(
  children: [

  ],
).center();

instead of wrapping them with Center:

Center(
  child:Column(
    children: [

    ],
)
);

카테고리

의존성

의존성 목록 1 개

소스 저장소

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

아직 데이터가 없습니다.