When developing an app with multiple screens, we tend to reuse the same piece of code over many classes: showing error messages, using the same page layout and wiring up some dependencies like for example a Bloc. All this could be solved if were using an
abstract base class, however, what if we have a set of features/classes that we want to use on a particular screen but not on others? Since a class can't be a child of more than one class, should we create different base classes, as much as the number of combinations that we have? That's why we have
Mixins and Base Classes: An introduction
Mixins let us add a set of “features” to a class without using parent-child hierarchy, allowing us to have in the same class one parent and multiple
mixin components. As such, since it’s not a parent of our class,
mixins don't allow any declaration of constructors. You can read more about them in this article by Romain Rastel with the caveat that Dart 2 now has the
mixin keyword, as seen in the documentation.
But how do
mixins work? Let's take as an example an
We can use this class as a parent using the
extend keyword, such as:
With this, we can initialize the class and call the parent’s method
But what if we want to add new features to
Mike? What if Mike is a coder and needs a
code function that could be used in other
Person, but is not used by all
mixin s save that problem.
First, we need to create a
mixin class and expose the new methods we want to use.
With the keyword
with, we can add this "feature" to our
And, as with the parent, we can call all the functions that we created in
Now every class that uses the
Coder can effectively code. However, this poses a problem: this means that if we have a parent class
Animal that has a child
Squirrel, we can also have a
Squirrel that can
code()! To prevent this, we can "lock" the usage of the
mixin to a class and all classes that inherited from it with the keyword
This also gives us a powerful tool: we can now override methods that were set in the
Person class to add or change functionality.
super.think() ensures that we are still calling the code that was defined in
Person. The above code gives us the following output for the method
By grasping the concepts of both
base classes and
mixin s we can now apply them to our Flutter apps.
Mixins and Base Classes: A practical Flutter Example
How can we apply this in our Flutter apps?
Take as an example the following two screens:
Our app has several screens with the layout shown above. Instead of copying and pasting the appbar and the background for each screen, we can solve our problem using
In both cases we have a screen title defined, we are going to create a
base class that has a method to provide our screen name called
BasePage. We also are going to apply the
mixins only in
StatefulWidgets since our classes will maintain and change their state. With this, we create two classes to be used in our pages: a
BasePage and a
BaseState<BasePage> that extend
Focusing on the second screen, we can now create its custom
BasicPageMixin, where we define the background and appbar of our page.
Since the method
body() doesn't have a body, each class that uses this
mixin must implement it, ensuring that we don't forget to add a body to our page.
In the screenshot above, we see a
FloatingActionButton, but we may not need it for every screen, so how can we define it? By declaring a new method,
fab() that by default returns a
Container. If a class needs to add a
FloatingActionButton, they can override this method.
mixin created, we can apply it to a new page.
And with this, we now only have to declare a
body() and a possible
fab() widget to be used in each screen, saving us a few dozens of lines of code.
As a new feature, some of our screens will make API calls and if an error occurs, we need to display an error message in the form of a Snackbar. Additionally, we decide to use the BLoC architecture in which we need to inject a new bloc when each page is created. These two problems will need the following steps:
- Change our
BasePageby changing its constructor with the new
BaseStateby adding a new
- Create a new
mixinthat let us display errors messages sent by the
blocin the page using a Snackbar
BaseBloc we are just exposing a
Sink and a
Stream in order to relay error messages.
Since we don’t want any other interactions with the
HomeBloc will just extend this class
We proceed by changing the constructor of our
BasePage to include the
bloc object. This will force us to also change all the classes that extend it to add the
bloc to their constructors too. The
bloc parameter is used as a Generic type so that each class that extends it can declare the correct type of bloc it is using. This makes sure that when we are calling it in the
BaseState , we are going to get the correct type of
bloc allowing us to access its methods.
As for the
BaseState, we are going to declare a
scaffoldKey to be used with the
ScaffoldWidget so that we can show the Snackbar.
As seen before, one of the curious properties of mixins is that if they are “linked” to a class, they can
override its methods. This is useful since in our
StatefulWidget we can
listen do the
streams in the
initState method. As such, to show the error messages, we can create a
mixin that overrides the
initState method and provides methods to show the error Snackbar with the correct message.
Finally, we can add it to our
HomePage class by adding it after the
And there we go! ✌️ Now we can use both
abstract classes to reuse code throughout our application.
Maybe we don't need to do a base UI for our app, but we can use
mixins like the
ErrorHandlingMixin to provide error feedback to the user, loading screens and showing a "App is Offline" screen.
However, creating both base classes and
mixins is a process that needs some deliberation, else we might face a "Deadly Diamond of Death", in which when calling one method that is declared in both base classes and
mixins, the compiler doesn't know which one to choose. You can read more about it in Shubham Soni 's article about
mixin s in Flutter.