State Managers : setState x ValueNotifier
Tags: flutter, mobile, dart
Published: 2021-12-30 15:56:55

State Management; probably the most controversial subject in the Flutter community. I remember when I started learning Flutter, [Provider](https://pub.dev/packages/provider) was the cool kid that everyone was recommending. Simple syntax, very detailed error messages, built on top of `InheritedWidget`, it was even featured on the official flutter docs, why would you even choose something else? I mean they got the **Approved By Google** badge, that's probably the highest status a package could get in the community 🤡.
Then came [Bloc](https://bloclibrary.dev/), personally, I don't know which one came first but I started hearing about Bloc a bit later after Provider. Bloc was making use of **Stream** which was something I always avoided because I didn't know much about how to handle streams. Bloc was and still is awesome when it comes to building big scalable apps, I am not saying that you can't do that with Provider, but Bloc seemed to specifically target that kind of project and it provides many built-in tools for a seamless developer experience. Some would argue that there is too much boilerplate, well as long as it does the job and does it well, you can go for it.

Besides Provider and Bloc, many other packages came up with very interesting approaches to handle the billion-dollar problem which is, of course, **State Management**, we have [Redux](https://pub.dev/packages/flutter_redux), [MobX](https://pub.dev/packages/flutter_mobx), [Riverpod](https://pub.dev/packages/flutter_riverpod), [Hooks](https://pub.dev/packages/flutter_hooks) and many others. But besides all those third-party packages, flutter has always had its own built-in tools to handle state management; and we are going to compare two of them: **setState** and **ValueNotifier**.

## setState
This is the most basic approach to updating your local state. Basically, `setState` is a method inside the `State` class that rebuilds the widget; it takes a `VoidCallback` as a parameter which is where you input all your variable updates, then after the widget is rebuilt, the changes you did in the `VoidCallback` parameter are applied in the newly built widget. The only requirement is to use a `StatefulWidget` because `StatelessWidget` doesn't have a state; it's literally `stateless` 😏. 
You might have come across `setState` in the boilerplate code generated by the `flutter create` command. It's not the best but it has its own advantages. Let's see an example of how to use it in a counter app.

```dart
import 'package:flutter/material.dart';

void main() {
  runApp(const App());
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomePage(),
    );
  }
}
class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _value = 0;
  @override
  Widget build(BuildContext context) {
    print('HOMEPAGE BUILT');
    return Scaffold(
      appBar: AppBar(title: const Text('Counter App')),
      body: Center(child: Text('Count: $_value')),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() => _value++);
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}
```
### The problem with setState
The problem with this approach is that it rebuilds the whole widget just to apply the changes passed in the parameter. If you run the code above, you will see `HOMEPAGE BUILT` printed in your console every time you press the `FloatingActionButton` on your app. 
This is not really a big problem when you have an app such as the one in our example, there is not much work to do there, just rendering a page with an app bar, a centered text, and a floating action button. 
What if below our centered text, we had multiple animated widgets that rebuild every second, let's say we have 50 containers that change their shape every five seconds to look like random characters from the Sponge Bob cartoon.
Well, now it becomes complicated because whenever the `FloatingActionButton` is pressed by the user, the whole `HomePage` widget will rebuild as well as the 50 sponge bob characters; many frames will be dropped and our app will become very junky.

Introducing **ValueNotifier** (with Tim Cook's voice).

## ValueNotifier
`ValueNotifier` is a class that holds a single value and can update the said value, and notifies only its listeners of the changes. `ValueNotifier` is often used with `ValueListenableBuilder` which is a widget that listens to changes from a `ValueNotifier` then rebuilds its child accordingly.
Kind of like the `private story` feature on Instagram. `setState` lets everyone know of your "story" but `ValueNotifier` lets only your closest friends know about your story. And to add someone to your private story, you gotta wrap them in a `ValueListenableBuilder` that listens to the same `ValueNotifier`. 
Let's remake our counter app with `ValueNotifier`.
```dart
import 'package:flutter/material.dart';

void main() {
  runApp(const App());
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final _counterNotifier = ValueNotifier<int>(0);

  @override
  Widget build(BuildContext context) {
    print('HOMEPAGE BUILT');
    return Scaffold(
      appBar: AppBar(title: const Text('Counter App')),
      body: Center(
        child: ValueListenableBuilder(
          valueListenable: _counterNotifier,
          builder: (context, value, _) {
            return Text('Count: $value');
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          _counterNotifier.value++;
        },
        child: const Icon(Icons.add),
      ),
    );
  }

  @override
  void dispose() {
    _counterNotifier.dispose();
    super.dispose();
  }
}
```
Now, whenever the counter value changes, only the `Text` widget in the center of our page rebuilds. If you open your console, you will see that the `HOMEPAGE BUILT` text is now printed only once even if you press that `FloatingActionButton` a thousand times.
You might have noticed that we are overriding the `dispose` method now. Well, that's because we want our `ValueNotifier` to stay only inside the `HomePage` and to disappear whenever the `HomePage` widget is disposed.

ValueNotifier can also be used to manage the global state, but for that, we will have to create our own Custom notifier that extends the ValueNotifier class. We will talk about it maybe another time.

I hope this article demystified some doubts you had about `setState` and `ValueNotifier`.
![Jojo's bizarre adventures: arrivederci](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f59a4a7umi50vs7folx7.png)