The better way to create  stateful widgets in flutter

The better way to create stateful widgets in flutter

Well, since you have come here, I can guess you are looking for some improvements in your coding and code quality. That's great!

Let's take a look at it how we can do it better :

While using the stateful widgets we need to be mindful of rebuilding the widget tree which significantly impacts the performance of your application. Here we will look at an example ( there can be many ways to achieve the same thing). In this example, we will make use of ValueNotifier and ValueListenableBuilder

Setup your Flutter project

Create a Flutter app

  •     flutter create example_app
    
  • Run your app

Now, we are done setting up the Flutter app, let's dive into the example.

Coding Example

In my main.dart file,

import 'package:flutter/material.dart';

void main() async {
  runApp( const MainApp()); // entry point of your application
}

// In this example, we have a stateless widget 
class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
             child: MySwitch() // MySwitch() is a stateful widget
        ),
      ),
    );
  }
}

What is ValueNotifier and ValueListenableBuilder?

ValueNotifier is a class that has a single generic type ( which means it can't hold more than one value) that specifies the type of value it holds. When the value it holds is changed it will trigger all the listeners listening to the changed value.

  ValueNotifier<bool> switchValue = ValueNotifier<bool>(false);

Here I have created a ValueNotifier that stores a boolean value that has an initial value of false.

We can use this ValueNotifier which in this case is switchValue to listen to the value and trigger the change of value to different available listeners.

ValueListenableBuilder is a widget that can listen and update the UI based on the value.

ValueListenableBuilder<bool>(
// valueListenable accepts the valueNotifier we have just created
      valueListenable: switchValue, 
// builder gives the current context, current value and the child it has to return
      builder: (BuildContext context, bool value, Widget? child) { 
        return Switch(
// switch takes the boolean value which is returned by builder method
          value: value,  
          onChanged: (newValue) { 
// onChanged return the value opposite to current value. eg 
// if the current value is false, it will return true

// Now we access the value inside of valueNotifier and change it with the value we got from onChanged Method           
 switchValue.value = newValue;  

/// when this value changed the builder method is re-run

          },
        );
      },
    );

Now that we understand how it works, let's wrap it up, in a line.

ValueListenableBuilder listens to the ValueNotifier that has a single generic value, on change of which ValueListenableBuilder will re-run the builder method, which reflects the change in UI without rebuilding the whole widget tree.

Full Code:

import 'package:flutter/material.dart';

void main() async {
  runApp(const MainApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(child: MySwitch()),
      ),
    );
  }
}

class MySwitch extends StatefulWidget {
  @override
  _MySwitchState createState() => _MySwitchState();
}

class _MySwitchState extends State<MySwitch> {
  ValueNotifier<bool> switchValue = ValueNotifier<bool>(false);

  @override
  void dispose() {
    switchValue.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    print("Widget rebuilding");
    return ValueListenableBuilder<bool>(
      valueListenable: switchValue,
      builder: (BuildContext context, bool value, Widget? child) {
        return Switch(
          value: value,
          onChanged: (newValue) {
            switchValue.value = newValue;
          },
        );
      },
    );
  }
}

I hope you got value out of this, if you did, you can subscribe to the newsletter that I will put out with updates and best practices.😉 For more, content like this, visit Flutter World.