When developing an app with multiple screens, we tend to reutilize the same piece of code over many classes: showing error messages, using the same page layout and wiring up some dependencies like a Bloc. All this could be solved if we are using an abstract
base class, however, what if we have a set of features/classes that we want to use? 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
.
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 mixing. As such, since it’s not a parent of our class, mixin
s 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 abstract class
Person
https://gist.github.com/d3ab28a11f2b5029c86e92a4c19f3351
We can use this class as a parent using the extend
keyword, such as:
https://gist.github.com/b42f94356f3069a5acf17727522efd2c
With this, we can initialise the class and call the parent’s method think()
.
https://gist.github.com/7f4f52e6314ae8472eb1e8b10130bc5e
But what if we want to add new features to Mike
? What if Mike is a coder and we want a code
function that can be used in other class, but is notused by all Person
s? mixin
s save that problem.
First, we need to create a mixin
class and expose the new methods we want to use.
https://gist.github.com/5587207a8dd1106952f7058552541ff5
With the keyword with
, we can add this “feature” to our Mike
class:
https://gist.github.com/dcbd10da8233f3bca173f783c67f6011
And, as with the parent, we can call all the functions that we created in Coder
.
https://gist.github.com/6a7be5d396a30998ba943018f65333a6
Now every class that uses the mixin
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 on
:
https://gist.github.com/0759d2ba8c512dce631aa6e999bed027
This also gives us a powerful tool: we can now override methods that were set in the Person
class to add or change functionality.
https://gist.github.com/d7bca3b3cd2595be1c0b38cb5a86b237
Calling the 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 think
in. Mike
:
https://gist.github.com/78afbff9996b7e9c6783c75a7573f000
By grasping the concepts of both base class
es and mixin
s we can now apply them to our Flutter apps.
How can we apply this in our Flutter apps?
Take as an example the following two screens:
[image:767784E9-572B-4E8A-9F36-3E83DDB5FBAC-72574-0000355858EF6919/Simulator Screen Shot - iPhone XR - 2019-05-06 at 19.35.42.png] [image:4D5FD1AB-0DBB-4FFE-9177-69E353B27E85-72574-00003558593DD800/Simulator Screen Shot - iPhone XR - 2019-05-06 at 19.35.53.png]
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 mixin
s. Let’s focus on the second one.
First, since 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. Second, we choose to apply these mixin
s only in StatefulWidgets
, however, since we already have a class that extends StatefulWidget
, we can state that our mixin
is only going to be applied to classes that extend BaseState<BasePage>
.
https://gist.github.com/b5f6f3279231d1f994d568f011928c24
Now we can create our BasicPageMixin
, where we define the background and appbar of our page.
https://gist.github.com/d79340427bd192092cb50a83d41c1a1b
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.
https://gist.github.com/a30e9e5f4e378398af60ffc98bcff26c
With this set, we can now create a new page with this mixin
and our base class
.
https://gist.github.com/dd9bdeb2e7459dd691ed6ed979cc5a0a
And with this, we now only have to declare a body()
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 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
BasePage
andBaseState
so that it has access to abloc
and add it to theBasePage
’s constructor - Create a new
mixin
that let us display errors messages sent by thebloc
in the page using a Snackbar
In our BaseBloc
we are just exposing a Sink
and a Stream
in order to relay error messages.
https://gist.github.com/24b3188f7dd84cea66c34adacbdb1659
Since we don’t want any other interactions with the bloc, our HomeBloc
will just extend this class
https://gist.github.com/e0c0c8ceeec0a044ac9b0db5402cf57a
To inject the bloc into our BasePage
classes, we need to make some amendments to our class, with one of them being making our class dependant of the type of bloc it has. In order to do that, we use Bloc
reference as a generic in the class statement.
https://gist.github.com/25a13b7ab78a0ba5fa92fe89bbe45491
This way, our BaseState
can access the correct bloc type using widget.bloc
.
As for the BaseState
, we are going to declare a scaffoldKey
to be used with the ScaffoldWidget
so that we can show the Snackbar.
https://gist.github.com/2c875737b6b90324fd5db4919451f7c1
As seen before, one of the curious properties of mixing 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 bloc
’s 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.
https://gist.github.com/6f563404e346f3ed2d4d038ed89b1955
Finally, mixin
s aren’t as constrained as a parent class, which we can only have one, so we can add it to our _HomePageState
.
https://gist.github.com/ec0747babf1b440a6e0b9a2df6fda6ca
And there we go!✌️ Now we can use both mixin
s and abstract class
es to reuse code throughout our application.
Maybe we don’t need to do a base UI for our app, but we can use mixin
s 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 mixin
s 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 mixin
s, 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.