The modular state management solution for flutter.

Overview

logo

The modular state management solution for flutter.

  • Easy debugging : each event is predictable and goes into a single pipeline
  • Centralized state : solid state validation
  • Power of async generators : writing asynchronous code is easy thanks to Dart generators

Quickstart

The global logical state of our application :

class CounterState {
  factory CounterState.initial() => const CounterState(0, 10);
  const CounterState(this.count, this.max);
  final int count;
  final int max;
  bool get isMax => count >= max;
}

The available actions that alterate the logical state of the application :

class AddAction extends Action<CounterState> {
  const AddAction(this.value);
  final int value;
  @override
  Stream<Updater<CounterState>> call(
    Context<CounterState> context,
  ) async* {
    yield (state) => CounterState(min(state.count + value, state.max), state.max);
  }
}

class ResetAction extends Action<CounterState> {
  @override
  Stream<Updater<CounterState>> call(
    Context<CounterState> context,
  ) async* {
    yield (state) => CounterState(0, state.max);
  }
}

class SaveAction extends Action<CounterState> {
  @override
  Stream<Updater<CounterState>> call(
    Context<CounterState> context,
  ) async* {
    await File(_cachePath).writeAsString(context.state.count.toString());
  }
}

class LoadAction extends Action<CounterState> {
  @override
  Stream<Updater<CounterState>> call(
    Context<CounterState> context,
  ) async* {
    final content = await File(_cachePath).readAsString();
    final count = int.parse(content);
    yield (state) => CounterState(min(count, state.max), state.max);
  }
}

The view that subscribes to the state changes and dispatches actions :

class MyHomePage extends StatelessWidget {
  MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Demo Home Page'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Builder(
              builder: (context) {
                /// This widget will be rebuilt each time the `count` value changes
                final count =
                    context.select((CounterState state) => state.count);
                return Text(
                  '$count',
                  style: Theme.of(context).textTheme.headline4,
                );
              },
            ),
          ],
        ),
      ),
      floatingActionButton: Builder(
        builder: (context) {
          /// This widget will be rebuilt each time the `isMax` value changes
          final isMax = context.select((CounterState state) => state.isMax);
          if (isMax) {
            return FloatingActionButton(
              /// The action is executed in the [ApplicationContext].
              onPressed: () => context.dispatch<CounterState>(ResetAction()),
              tooltip: 'Reset',
              child: Icon(Icons.delete),
            );
          }

          return FloatingActionButton(
            /// The action is executed in the [ApplicationContext].
            onPressed: () => context.dispatch<CounterState>(AddAction(1)),
            tooltip: 'Increment',
            child: Icon(Icons.add),
          );
        },
      ),
    );
  }
}

The state initialization at the root of the tree with the Fountain widget :

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Fountain(
      initialState: (context) => CounterState.initial(),
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(),
      ),
    );
  }
}

Core concepts

schema

Context

The application context maintains a unique global logical immutable state for the application.

The context also contains all the middlewares that will process the dispatched event.

The application context is provided to the widget tree from a Fountain so that any descendent widget can observe a property of the state with the select extension method. It can also dispatch events into the middlewares with the dispatch extension methods.

Middleware

The application middleware process the dispatched Events and can produce state updates.

They are composable by nature which means that each middleware can wrap another middleware.

Event

The events are inputs for middlewares. They can describe a user action, or a system event for exemple. They are processed by the middlewares which can produce new application states.

Included middlewares

To import middlewares, use the import 'package:fountain/middlewares.dart'; directive.

Actions

By default, the framework includes a ActionExecutor middleware that allows to define Action s which are then invoked directly to produce new states.

Defining an action

To create custom actions, inherits from Action and implement all of the update logic in the call method. Since the method returns a Stream, a convenient way to implement the logic is often by using async * generators which allows to yield a sequence of state updates.

class RefreshAction extends Action<MyApp> {
  const RefreshAction();

  @override
  Stream<Updater<CounterState>> call(
    Context<CounterState> context,
  ) async* {
    if(!context.state.isLoading) {
        yield (state) => state.copyWith(
            isLoading: true,
        );

        final news = await Api.instance.getNews();

        yield (state) => state.copyWith(
            isLoading: false,
            news: news,
        );
    }
  }
}

Note that the actions aren't yielding states directly, but Updaters. This is to insist on the fact the the initial state may have changed during the action execution, and therefore, it must be taken into account when updated.

Logging

The framework also includes a Logging middleware that logs all events and state updates.

Fountain(
    middlewares: <Middleware<CounterState>>[
        Logging<CounterState>(),
        ...Fountain.defaultMiddlewares<CounterState>(),
    ],
    // ...
);

ErrorHandler

This middleware catches all unmanaged exceptions from middlewares below it and dispatches new events if so.

Fountain(
    middlewares: <Middleware<CounterState>>[
        ErrorHandler<CounterState>(
            (context, event, initialState,error,stackTrace) {
                // An unknow error occured during event processing
                return DisplayAlertAction('Sorry, an error occured');
            },
        ),
        ...Fountain.defaultMiddlewares<CounterState>(),
    ],
    // ...
);

About

Wait ... yet another state management solution for Flutter ?

Fountain is not so new to me, I've used this approach for a longtime now. Centralizing it as an opensource library makes a lot of sense to create a standard for a all of my personal and professional projects.

Inspired by

This project stands on the shoulders of giants, with the intention of reducing boilerplate, being minimalist and simple at its core.

  • Redux for the functional update cycle and general principles, with the purpose of having less boilerplate by being a bit more opiniated.
  • Express | Koa for their composability and modularity thanks to middlewares.
  • Bloc for its use of Streams.
  • Provider for its select method.

How is it different from other popular solutions ?

  • Provider : Fountain is more opiniated than Provider, and thus Provider is a more general purpose tool. Provider is often used in combination with a ChangeNotifier to create a simple state management solution.
  • Redux : Fountain has the same overall philosophy than Redux with Thunks but brings less boilerplate when dealing with asynchronous logic with ApplicationActions logic by using Streams. Fountain also brings the middleware concepts.
  • Bloc : Fountain use a global state instead of various Blocs. We believe it is important since there's a lot of areas which need to be aware of another part of your app logic. This makes also persistence, testability easier to deal with.
You might also like...

Example of use bloc + freezed with a state that contains a list

blocfreezedlistexample A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you s

Mar 21, 2022

Timer based on provider state manager

timer_provider Timer based on provider state manager Getting Started This project is a starting point for a Flutter application. A few resources to ge

Nov 6, 2021

Trip management mobile Application

Trip management mobile Application

HereYouGO Trip management mobile Application This app will help you Track your expense during your trips. Track your trip destinations and the sub tri

Jul 7, 2022

Functional programming in Dart and Flutter. All the main functional programming types and patterns fully documented, tested, and with examples.

Fpdart Functional programming in Dart and Flutter. All the main functional programming types and patterns fully documented, tested, and with examples.

Dec 26, 2022

⚡FQuery is a powerful async state management solution for flutter. It caches, updates and fully manages asynchronous data in your flutter apps.

⚡ FQuery is a powerful async state management solution for flutter. It caches, updates and fully manages asynchronous data in your flutter apps. It ca

Dec 22, 2022

Flutter Control is complex library to maintain App and State management. Library merges multiple functionality under one hood. This approach helps to tidily bound separated logic into complex solution.

Flutter Control is complex library to maintain App and State management. Library merges multiple functionality under one hood. This approach helps to tidily bound separated logic into complex solution.

Flutter Control is complex library to maintain App and State management. Library merges multiple functionality under one hood. This approach helps to

Feb 23, 2022

A super-fast and efficient state management solution for Flutter...

turbo A super-fast, efficient state management solution for Flutter. Turbo does not use streams, which are extremely inefficient, or use complex abstr

Oct 16, 2022

GetX - one of the most popular state management solution in flutter

GetX - one of the most popular state management solution in flutter

GteX Tutorial - Udemy GetX is one of the most popular state management solution in flutter. In addition to state management, GetX provides easy way to

May 18, 2022

A flutter state management solution.

A Flutter State Management solution with dependency injection Usage Create your business logic class and place all variables, methods inside it. impor

Dec 15, 2022

Another state management solution

VxState VxState is a state management library built for Flutter apps with focus on simplicity. It is inspired by StoreKeeper & libraries like Redux, V

Dec 24, 2022

Cubit is a lightweight state management solution

Cubit is a lightweight state management solution

Cubit is a lightweight state management solution. It is a subset of the bloc package that does not rely on events and instead uses methods to emit new states.

Nov 23, 2022

This repo is an example of clean architecture using the GetX state-management solution.

This repo is an example of clean architecture using the GetX state-management solution.

GetX Clean Architecture A Flutter Clean Architecture Using GetX. This repo is forked from: https://github.com/phamdinhduc795397/flutter-getx-clean-arc

Jan 3, 2023

A simple state management solution that combine the power of inherited widget and rxdart

Inherited RxDart is a state management library that combine the power of InheritedWidget and RxDart, a simple and elegant state management solution for apps of any scale

Oct 26, 2022

Modular Get Flutter

Modulex Um framework para desenvolvimento de aplicativos escalaveis e modulares. Motivacao Sempre utilizei o Getx em meus projetos, porem, acho ele mu

May 15, 2022

Flutter Modular - A smart project structure

Flutter Modular - A smart project structure

Flutter Modular Getting started with Modular flutter_modular Documentation flutter_modular_test Documentation modular_codegen Documentation Features a

Jan 5, 2023

Github Search - Flutter Modular example

Github Search - Flutter Modular example

Desafio Github Search Projeto desenvolvido no desafio quizenal realizado pela equipe Flutterando e comunidade. Foram realizadas adaptações para implem

Nov 6, 2021

Projeto utilizado para estudo do Slidy, Flutter Modular, Mobx e novos conceitos de UI, desenvolvido com base em curso online.

my_workout A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if th

Sep 9, 2022

A basic Modular app

lifecare_app A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if

Jan 10, 2022

Modular server framework with ConnectMe (WebSockets + PackMe) and MongoDb support.

What is ServeMe ServeMe is a simple and powerful modular server framework. It allows to easily create backend services for both mobile and web applica

Dec 3, 2022
Comments
  • Add Portuguese translation and structure for other translations

    Add Portuguese translation and structure for other translations

    As @irvine5k said in issue #1, this is very interesting project. So, for we Brazilizan and other people that speak Portuguese, I added the translation to follow the project progress and as reference, when it gaining more attention (and I think it will😊).

    opened by robsonsilv4 0
  • Provide a more complex example

    Provide a more complex example

    I was from the time of Scoped Model, so I tried a lot of approaches of state management and I can say that Fountain is really interesting, and by the docs and visual identity, I can see that you put your heart into it. Nice job!

    I liked the idea of separate actions instead of a class that handles all of them. The state injection in the widget tree is really easy, and since it's a global state, we can eliminate duplicated code(Providers everywhere). You brought the redux idea of middlewares, which is really useful to automate some boilerplate stuff like Analytics, Logging, Mock.

    I only miss a more complex example that can better explain how the global state is built and the view listens only to one part of it.

    documentation enhancement good first issue 
    opened by irvine5k 7
Owner
Aloïs Deniel
Flutter Freelance
Aloïs Deniel
MobX for the Dart language. Hassle-free, reactive state-management for your Dart and Flutter apps.

Language: English | Português | Chinese mobx.dart MobX for the Dart language. Supercharge the state-management in your Dart apps with Transparent Func

MobX 2.2k Dec 27, 2022
A flutter boilerplate project with GetX state management.

flutter_getx_boilerplate Languages: English (this file), Chinese. Introduction During my study of Flutter, I have been using the flutter_bloc state ma

Kevin Zhang 234 Jan 5, 2023
Flutter MVU architecture/state management package

mvu_flutter No mutability. No builders. No connectors. No reducers. No StreamControllers and subscription management. A truly declarative state manage

Yakov Karpov 7 Jul 29, 2021
Simple global state management for Flutter

Slices Slices is a minimalist state manegement, focused specifically for applications that needs a global state where different "pieces" of the applic

Erick 5 Jun 15, 2021
Flutter State Management with provider :rocket:

Flutter - Gerenciamento de Estados com Provider Objetivos ao completar os estudos Aprenda a gerenciar o estado da sua aplicação com Single Source of T

Tiago Barbosa 0 Dec 6, 2021
A predictable state management library that helps implement the BLoC design pattern

A predictable state management library that helps implement the BLoC design pattern. Package Pub bloc bloc_test flutter_bloc angular_bloc hydrated_blo

Felix Angelov 9.9k Dec 31, 2022
London App Brewery State Management Project

todey_flutter A new Flutter application. Getting Started This project is a starting point for a Flutter application. A few resources to get you starte

null 0 Nov 1, 2021
A simple way to access state while robust and testable.

A state-management library that: catches programming errors at compile time rather than at runtime removes nesting for listening/combining objects ens

Remi Rousselet 3.9k Jan 3, 2023
A lightweight, yet powerful way to bind your application state with your business logic.

binder A lightweight, yet powerful way to bind your application state with your business logic. The vision As other state management pattern, binder a

Romain Rastel 172 Nov 16, 2022
Manage the state of your widgets using imperative programming concepts.

Imperative Flutter Manage the state of your widgets using imperative programming concepts. Setup Intall imperative_flutter package in pubspec.yaml dep

Jeovane Santos 5 Aug 20, 2022