Build in Flutter, Without set state and Stateful Widget

How does the build method work in Flutter? In this section we’ll take a look at the core concept of Flutter.

In our previous section we have seen a simple Stateful widget where we have used a counter to press the button and change the internal state of the object. As a result, it calls the build method in Flutter each time we press the button.

We passed setState to that function where we made the change. But that didn’t stop calling the build methods of the other widgets. 

However, the has rebuilt the widgets that we haven’t intended to. In addition, that has also reduced the performance.

Therefore we need to change the way we change the State of the object.And to do that we need to change the State without calling setState.

Firstly, we will see the simple counter app we’ve built without a set state method and Stateful widget.

Secondly we’ll see and discuss the code.

Finally, we have used the Material You design to give the counter app a special look.

Build in Flutter with a Counter app
Build in Flutter with a Counter app

As the image shows, we have pressed the button 4 times. Right? 

As an outcome, we have got this output.

Third Build
Third Build
Third Build
Third Build

It clearly shows, each time we press the button, it calls the build method in Flutter. But it has not rebuilt the whole widget tree. Not only that, it has not called all the build methods of child widgets. Which is a great performance booster.

However, in our previous counter app with set state and Stateful widget, what did we see as output?

Let’s take a look.

print MyHomePageState
print Center Widget
print Column Widget
print MyHomePageState
print Center Widget
print Column Widget
print MyHomePageState
print Center Widget
print Column Widget
print MyHomePageState
print Center Widget
print Column Widget

Build in Flutter, with Provider

Now the question is how we have reduced the widget rebuilds? As an outcome the Flutter app only calls the build method of the widget that handles the value. 

It does not call the build method of the parent widgets.

But when we use set state and Stateful widget, it doesn’t happen.

The answer is the Provider package. Provider is nothing but a wrapper around InheritedWidget. Certainly we could manually write the same thing using Inherited Widget. 

But Provider has made things simple.

Provider has many advantages over set state and Stateful widget.

The biggest one is it does not unnecessarily call the build methods in Flutter. 

Let’s take a look at the full code. That will certainly explain the rest.

import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';

import 'model/counting_the_number.dart';
import 'model/theme.dart';

final settings = ValueNotifier(
  ThemeSettings(
    sourceColor: Colors.yellow.shade900,
    themeMode: ThemeMode.system,
  ),
);

void main() => runApp(
      ChangeNotifierProvider(
        create: (context) => CountingTheNumber(),
        builder: (context, _) => DynamicColorBuilder(
          builder: (lightDynamic, darkDynamic) => ThemeProvider(
            lightDynamic: lightDynamic,
            darkDynamic: darkDynamic,
            settings: settings,
            child: const FlutterMaterial(),
          ),
        ),
      ),
    );

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

  static const String _title = 'Flutter 3.0 Notification & Material 3';

  @override
  Widget build(BuildContext context) {
    print('First Build');
    final theme = ThemeProvider.of(context);
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: theme.dark(settings.value.sourceColor),
      darkTheme: theme.dark(settings.value.sourceColor), // Add this line
      themeMode: theme.themeMode(),
      title: _title,
      home: const MyHomePage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    print('Second Build');
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'How Many Widget Builds',
          style: GoogleFonts.alexBrush(
            fontSize: 30.0,
            color: Theme.of(context).colorScheme.error,
          ),
        ),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
              style: GoogleFonts.charm(
                fontSize: 40.0,
                color: Theme.of(context).colorScheme.outline,
              ),
            ),
            const Count(),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        key: const Key('increment_floatingActionButton'),

        /// Calls `context.read` instead of `context.watch` so that it does not rebuild
        /// when [Counter] changes.
        onPressed: () => context.read<CountingTheNumber>().increaseValue(),
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    print('Third Build');
    return Text(
      /// Calls `context.watch` to make [Count] rebuild when [Counter] changes.
      '${context.watch<CountingTheNumber>().value}',
      key: const Key('counterState'),
      style: Theme.of(context).textTheme.headline2,
    );
  }
}

We have a separate category on Provider that discusses its best practices to manage state and passing any type of data.As we progress, we’ll see more and more usages of Provider packages such as Consumer, Selector, Change Notifier Provider and many more.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

Courses at Educative

GitHub repository

Python and Data Science

Twitter

Comments

Leave a Reply