搜索插件、代码仓与 APP 分类

插件详情v0.0.5

sprinkle

一种便捷的基于流的 Flutter 架构

近 30 天下载
15
喜欢数
17
Pub 分数
10

安装插件

flutter pub add sprinkle

插件介绍

基于插件公开信息、社区数据与项目使用情况整理的选型参考。

Sprinkle 是一种基于流的 Flutter 架构,旨在实现简单性和可扩展性。它通过流利用响应式编程来管理状态和依赖关系,从而在应用程序中实现高效的数据流。Sprinkle 采用清晰的关注点分离,通过将业务逻辑与 UI 组件解耦,促进可测试性和可维护性。它能无缝集成到 Flutter 的组件树中,并支持依赖注入,非常适合中大型应用。该包强调开发人员体验,具有最少的样板代码和直观的模式。

适合场景

  • 响应式 UI 更新
  • 复杂应用中的状态管理
  • Flutter 中的依赖注入
  • 流驱动的数据流
  • 测试和调试工作流

主要特点

  • 基于流的状态管理
  • 内置依赖注入
  • 最小化样板代码
  • 可测试的架构
  • 关注点的清晰分离

适合对象

  • 中大型 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 项

源码仓库

使用此插件的项目

暂无相关数据。