Skip to content

Software Development at Program Tom LTD

Place for coding, programming, development and software in general.

Menu
  • Blog
  • PDF Booklets
  • Dev Utils & Content
  • Java Spring Boot Or Web Apps
  • English
    • български
    • English
    • Español
    • Português
    • हिन्दी
    • Русский
    • Deutsch
    • Français
    • Italiano
    • العربية
  • About Us
  • Flutter Apps
Menu
Minimal Code of Flutter App using Provider State Management

Minimal Code of Flutter App using Provider State Management

Posted on September 9, 2024 by Toma Velev

You could lift up the state of your widgets in your Flutter App and it could become independent with Minimal Code using Provider State Management and Go Router for a navigation.

Any meaningful app has

  • Multiple Screens
  • Cross Screen State
  • Single Screen Only State

You could implement

  • Navigating between screens with Go Router.
  • Having Cross Screen State (Inter-Feature Communication) – with Global Provider Definition
  • Providers only for around single Screen only

Whatever State Management – you will find this common pattern – Have a Screen / Feature / Minimally, but fully funcitonal and independent component. So any of these – will have their own

  • directory with:
    • views/components
    • dependency injection definitions
    • local providers, blocs, cubits, Get Services

With this archtecture – you could get rid of great majority of your StatefulWidgets.

Minimal Code of Flutter App

main.dart

The main.dart may be the place for global definitions:

MultiProvider(
          providers: [
            ChangeNotifierProvider(create: (_) => yourGlobalService()..fetchData()),
          ],
          child: const MyApp(),
        )

my_app.dart

My App is the common place to define global settings, bindings, definitions. Here is also the place for the router.

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

  final _router = GoRouter(
    routes: [
      GoRoute(
        path: '/',
        builder: (context, state) => MultiProvider(
          providers: [
            ChangeNotifierProvider(create: (_) => LocalService()..fetchData()),
          ],
          child: const FirstScreen(),
        ),
      ),
      GoRoute(
        path: '/second',
        builder: (context, state) => const SecondScreen(),
      ),
    ],
  );

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
    );
  }
}

my_service.dart

import 'package:flutter/widgets.dart';

class MyService extends ChangeNotifier {
  bool isLoading = false;
  bool success = false; // Tracks whether the network call was successful

  Future fetchData() async {
    isLoading = true;
    success = false; // Reset success before making a new call
    notifyListeners();

    Future.delayed(
      const Duration(seconds: 2),
      () {
        success = true;
        isLoading = false;
        notifyListeners();
      },
    );
    // final response = await http
    //     .get(Uri.parse('https://programtom.com/dev'));
    //
    // if (response.statusCode == 200) {
    //   success = true;
    // } else {
    //   success = false;
    // }
  }
}

Use Consumer in FirstScreen:

Here, we refactor FirstScreen to use Consumer, which listens for changes in NetworkProvider‘s state and reacts accordingly.

import 'package:file_sharing_app/services/LoginService.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:go_router/go_router.dart';

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

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text('First Screen')),
        body: Center(
          child: Consumer(
            builder: (context, networkProvider, child) {
              // Check if the network call was successful and navigate
              if (networkProvider.success) {
                Future.microtask(() {
                  if (context.mounted) {
                    GoRouter.of(context).replace('/second');
                  }
                });
              }

              return networkProvider.isLoading
                  ? const CircularProgressIndicator()
                  : ElevatedButton(
                      onPressed: () {
                        // Trigger the network call
                        networkProvider.fetchData();
                      },
                      child: const Text('Loading ...'),
                    );
            },
          ),
        ),
      );
}

Second Screen

import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) => const Scaffold(
        body: Text("second"),
      );
}

Key Points:

  • Consumer<MyService>: Reactively listens to changes in the MyService state and rebuilds the widget when changes occur. If you want to optimize – use Selector – to specify only one field from the Provider – minimizing the UI rebuilds.
  • Navigation with Future.microtask(): Since Flutter’s build method might be called multiple times during a rebuild, we use Future.microtask() to ensure navigation happens after the current frame finishes rendering.
  • No StatefulWidget: This solution eliminates the need for StatefulWidget, since the Consumer takes care of reacting to state changes.

Explanation:

  • Consumer<NetworkProvider> rebuilds whenever isLoading or success changes.
  • If success is true, navigation to the second screen is triggered.
  • When the button is pressed, the fetchData() method is called, and changes in the provider are reflected by Consumer rebuilding the widget tree.

This approach is simple, efficient, and reactive, eliminating the need for managing state manually via StatefulWidget.

  • Example of GridView Builder in Flutter
  • How to Visualize Listview inside Listview in Flutter
  • What other usages you know about public private cryptography
  • Get a Flutter App to Production
  • Firebase Dynamic Links Deprecation – migrating out to Java

Categories

  • Apps (20)
  • ChatGPT (19)
  • Choosing a Framework (38)
  • Flutter (201)
  • Graphical User Interface (13)
  • Marketing (113)
  • Software Development (268)
  • Spring (41)
  • StartUp (21)
  • Uncategorized (15)
  • Uncategorized (4)
  • Vaadin (14)

Tags

Algorithms (9) crypto (29) flutterdev (39) General (86) Java (7) QR & Bar Codes (3) Software Dev Choices (33) Spring Boot (1) standards (1) Theme (3) User Authentication & Authorization (9) User Experience (10) Utilities (19) WordPress (11)

Product categories

  • All Technologies (83)
    • Flutter Apps (23)
    • GPT (4)
    • Java (38)
    • Native Android (3)
    • PHP (9)
    • Spring (Boot) / Quarkus (35)
    • Utils (15)
    • Vaadin 24+ (27)
    • Vaadin 8 (1)
  • Apps (18)
    • Employees DB (1)
    • Notes (6)
    • Personal Budget (1)
    • Recipes Book (1)
    • Stuff Organizer (1)
    • To-Do (2)
  • PDF Books (3)
  • Source Code Generators (8)

Recent Posts

  • Example of GridView Builder in Flutter
  • How to Visualize Listview inside Listview in Flutter
  • What other usages you know about public private cryptography
  • Get a Flutter App to Production
  • Firebase Dynamic Links Deprecation – migrating out to Java

Post Categories

  • Apps (20)
  • ChatGPT (19)
  • Choosing a Framework (38)
  • Flutter (201)
  • Graphical User Interface (13)
  • Marketing (113)
  • Software Development (268)
  • Spring (41)
  • StartUp (21)
  • Uncategorized (15)
  • Uncategorized (4)
  • Vaadin (14)