The Flutter GetX Ecosystem ~ State Management

Aachman Garg
Flutter Community
Published in
7 min readAug 30, 2020

Flutter is awesome! It’s by far the fastest way to create truly cross platform apps without compromising beauty, performance and features. With development experience unlike any other framework, it does tick most of the boxes. However, it’s not perfect. There are some things that slow down the development from time to time.

Take for example, the boiler plate while implementing BLoC pattern or the time consumed by code generator in MobX or even the extra long syntax of Navigator and MediaQuery. All this hits the overall development experience with more lines of code and less efficiency.

Enter GetX!

GetX is a micro-framework that aims to provide top notch development experience by minimizing the boiler plate combined with neat syntax and simple approach. When developing with GetX, everything feels self evident and practical. It’s a solid blend of simplicity and power. It’s one of those rare packages that try to do everything and actually do it.

GetX provides a combination of State Management, Dependency Injection and Route Management solutions that work great together. But things don’t end here, it provides a ton of utilities that make it easy to implement internationalization, theming, validation, etc.

All of these solutions and utilities are packed in individually compiled containers which gives us the freedom to choose what to use and what not to, without compromising performance. However, once you’re using GetX, it’s hard to not use everything this package has to offer, because everything works so seamlessly together. And, that’s what I call The GetX Ecosystem.

What’s so special?

  • Firstly, I love the syntax! Before I used GetX, I couldn’t imagine that things like navigating to a route can be made this simple. We don’t need context, builder or anything. Just write Get.to(SomePage()) and that's it. And that's just one example.
  • Primary focus is on performance. Normally, we would have to choose which controllers to dispose and manually dispose them. With GetX, it’s the opposite. We have to choose which one to keep in the memory as they are disposed automatically. Saves memory, and lines of code.
  • 100% Decoupling! With GetX, it’s actually possible to achieve this. Business logic is separated from views, and even dependencies can be separated using something called Bindings.
  • It just works. Working with GetX is quite a satisfying experience. Whenever I’ve to implement a certain feature, there’s always a simpler way to do it with GetX, no matter the use case.
  • It’s well maintained and up-to-date. It can be challenging to keep all your packages updated and in sync with each other. Sometimes, there are breaking changes and things can get nasty. GetX centralizes most of our development needs under one package, so we don’t need to worry about compatibility and maintenance.

State Management? State Management!

State Management is still the hottest topic in Flutter Community. There are tons of choices available and it’s super intimidating for a beginner to choose one. Also, all of them have their pros and cons. So, what’s the best approach? Answer is simple — The one you feel comfortable with. Can GetX be the one? Let’s take a look!

GetMaterialApp

Step 0 : Use GetMaterialApp instead of MaterialApp.

Boom! Now you’re officially in the ecosystem.

Note: GetMaterialApp is optional if you’ll be using GetX only for state management, and actually used when managing routes, which we’ll cover in future articles.

GetxController

Controllers are classes where all our business logic goes. All the variables and methods are placed here and can be accessed from the view. While we can just create a simple class for this purpose, GetX provides a class called GetxController which extends DisposableInterface.

This means that our controller will get deleted from memory as soon as the widgets using it are removed from the navigation stack. We don’t have to manually dispose anything and the memory consumption is reduced, resulting in high performance.

GetxController comes with onInit() and onClose() methods which essentially replace the initState() and dispose() methods of the StatefulWidget. This allows us to completely avoid using StatefulWidget and write highly organized code.

GetBuilder

GetBuilder can be wrapped over any widget to make it interact with the methods and variables of the controller. We'll be able to call functions, listen to state changes, etc.

So, let’s create a controller first.

We use update() method inside any method in the controller so that our widgets can listen to the changes made by the method. If you have used Provider package, it's just like notifyListeners().

Now to make it work on the UI side, we wrap our widget with a GetBuilder.

You need to initialize Controller only the first time it's used in GetBuilder. All other GetBuilders will automatically share the state of the first one, no matter where they are in the app.

GetBuilder essentially replaces the StatefulWidget. You can keep all the pages Stateless and wrap specific widgets in GetBuilder. It's a nice way to manage ephemeral state, while keeping the code organized.

We also get a refined control over which widgets to update by assigning unique IDs.

GetX

GetBuilder is fast and has low memory footprint, but, it's not reactive. This means we'll be missing out on the power of streams. Well, for this very reason, GetX (class) was created.

GetX is very similar to GetBuilder in terms of syntax, but the approach is purely stream based.

Let’s see how it works:

Add .obs to any variable and you make it observable. Basically you're turning counter into a stream of type int. This means that we can listen to the changes made to counter from our view using GetX.

GetX<Controller> is basically a StreamBuilder without boilerplate.

counter is of type RxInt and to actually use it, we need to add .value to it. We have to do this with any kind of observable variable.

What if we want to make a class object observable? Well, it’s the same process. In one line of code, we can make all the variables of the class observable. Neat. I’ll show that while implementing Obx.

Obx

This one is a personal favorite. It has the simplest syntax and implementation. All we’ve to do is wrap the widget in Obx(() ⇒ ) and we're done!

The syntax is shorter than setState, though there's one extra step here. We need to initialize the Controller to use our variables and methods.

This is how we do it in GetX:

What’s happening here? Putting it this way makes the controller available in all the child routes of this class. We'll be able to get the same instance from anywhere in the app in a simple way. This will help us make multiple widgets interact with same controller in an organized way.

Now, to use the same instance in another class:

GetX will automatically find the instance we used previously, no matter where it is in the widget tree. Now, if we change the value of a controller variable from PageSeven, it'll be updated in PageOne as well.

Which one to choose?

GetBuilder

  • When maintaining ephemeral state. Which basically means use it wherever you would use setState.
  • If performance is the top most priority. State is shared among builders and much RAM is not consumed.
  • If you don’t want to work with streams.

GetX

  • When you want the power of reactive programming.
  • It redraws the widget only when the value of variable is actually changed. Say value of variable is changed from "Garg" to "Garg", then widgets will not be redrawn.
  • If you don’t want to instantiate controllers.

Obx

  • If you prefer a simple syntax.
  • If you’ll be using with multiple controllers in the same widget. Obx doesn't need a type, so it can be used with any number of controllers. Something like this:
  • When using Bindings (we’ll discuss in the next article), always prefer Obx

MixinBuilder

What?! There’s another one? Yes, there is. As the name suggests, it mixes two of the above approaches, which are GetBuilder and Obx. With MixinBuilder, we can use use "Aachman" and "Aachman".obs in the same widget.

Isn’t that cool? Why is it not discussed above? Well, because of two reasons:

  • It’s the heaviest of all other approaches, so will affect the performance in larger apps.
  • It has a very specific and rare use case, which we may never come across.

Still, if it works for you, go ahead and use it. Here’s the syntax!

What’s my approach?

For the most part, I use Obx with Bindings as it allows the use of multiple controllers. For very simple widgets, where ephemeral state needs to change, I use GetBuilder.

For example, if a button changes it’s color, when pressed. In this case, working with streams will be an overkill, and natural choice would be setState. But our goal is to avoid using StatefulWidget and keep business logic separated from view. GetBuilder is perfect for such use cases.

That’s it!

This was the GetX approach to State Management, which I feel is one of the best solutions out there. I hope this package and this article adds value to your Flutter development experience.

What’s next?

Here’s the link to GetX package: https://pub.dev/packages/get

Read Portuguese translation by Fábio Jansen

Read Spanish translation by mal2tin

Read Japanese translation by inari_sushio

Check out my previous work!

Any questions or suggestions? Put them all in the comments section :D

Liked the article? Press and hold on the 👏 button! That’ll motivate me to write more and more!

You can find me on LinkedIn, stalk my GitHub, follow me on Twitter or email me at imaachman@gmail.com for any kind of tech discussion.

--

--