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.
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!
Step 0 : Use
GetMaterialApp instead of
Boom! Now you’re officially in the ecosystem.
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.
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
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
onClose() methods which essentially replace the
dispose() methods of the
StatefulWidget. This allows us to completely avoid using
StatefulWidget and write highly organized code.
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.
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
Now to make it work on the UI side, we wrap our widget with a
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.
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:
.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<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
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?
- When maintaining ephemeral state. Which basically means use it wherever you would use
- 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.
- 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", then widgets will not be redrawn.
- If you don’t want to instantiate controllers.
- If you prefer a simple syntax.
- If you’ll be using with multiple controllers in the same widget.
Obxdoesn'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
What?! There’s another one? Yes, there is. As the name suggests, it mixes two of the above approaches, which are
MixinBuilder, we can use use
"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
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.
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.
The Flutter GetX Ecosystem ~ Dependency Injection
— Coming soon!
Here’s the link to GetX package: https://pub.dev/packages/get
Read Portuguese translation by Fábio Jansen
O Ecossistema Flutter GetX ~ Gerenciamento de estado
Esta é a versão em Português do excelente artigo em Inglês escrito por Aachman Garg.
Check out my previous work!
Flutter Calendar Using BLoC Architecture
Go beyond UI, learn to build real world apps using BLoC pattern in Flutter.
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!