DEV Community

loading...
Cover image for 11 Beginner Tips for Google's Flutter

11 Beginner Tips for Google's Flutter

Zack Hoherchak
Originally published at Medium ・7 min read

11 Beginner Tips for Google's Flutter

Flutter has established itself as a major player in the cross-platform space. I've been working on a Flutter app for the last 30 days, and here are a few things I've learned.

Trailing Commas Are Not Optional

Keyboard shortcuts are great for speeding up productivity, and I tend to spam my "format code" keybind When I first started using Flutter, I was baffled about why sometimes my code would clean itself up, and other times it would remain a tangled mess. The Flutter dart formatter only works when you use trailing commas!

Without Commas
Without Commas

With Commas
With Commas

Keep it Stateless

Widgets are better without state. There are definitely scenarios where you will need to use a StatefulWidget, but use stateless widgets wherever possible! Handling state in other ways (see the "state" tip below) will make your code more maintainable in the future. Using factories can help with setting up stateless widgets. I use Google's Firestore, and providing a factory is a great way to map your data to a strongly typed object and keeping your widget stateless.

Flutter Factory
Flutter Factory

How to Handle Type Conflicts

Dart exposes all of the available classes from the import, which comes at great convenience when you are not familiar with the exact name of the class you need, but can cause some overlap causing the compiler not to understand which classes you want to use. The application I'm working on uses many generic terms/classes, often causing these overlaps and causing obscure errors if you are unfamiliar with Flutter.

Full Import
Full Import

There are a few ways to avoid this situation. The first and my favorite is to hide the conflicting class.

Import with Hidden Class
Import with Hidden Class

You can also specify all of the classes that you need from the import, which normally sounds favorable to me, but in this case, it can get a little verbose.

Import with Specific Classes
Import with Specific Classes

Lastly, if you actually need both classes in the same place, you will have to provide a prefix/alias to access what you want.

Import with Alias
Import with Alias

Hide The Ugly Banner

When I ran the starter app, the first thing I wanted to do was remove the ugly debug banner from the Material banner. You can add the debugShowCheckedModeBanner flag to your material app.

Debug Banner
Debug Banner

debugShowCheckedModeBanner: false
Enter fullscreen mode Exit fullscreen mode

Streams & Futures (Asynchronous Data)

Handling asynchronous actions is one of the most important things in any framework because every app connects to something somewhere. Coming from Typescript, I'm more familiar with the terms promise and observable, but the best ways to handle futures and streams in flutter is with FutureBuilder and StreamBuilder. These widgets take two main parameters, the call loading the data and a builder, which acts as the standard build method on StatelessWidget that updates when the request completes.

FutureBuilder
FutureBuilder

Since my application does not need any fancy loading animations, I decided to set up a global loading widget inside a snapshot resolver class, so I'm not repeating the same if/else combination throughout my app.

Snapshot Resolver
Snapshot Resolver

If your app needs more complicated custom animations depending on what is loading, then this resolver class is not for you, but the implementation would look the same, checking if the snapshot has data, an error, or otherwise return your loading widget.

More Widgets, More Better

The first time I tried flutter (early 2019), I gave up on it quickly simply because I was not too fond of the nesting widgets structure. If you are not careful, you will end up with what I call triangle code

Triangle Code
Triangle Code

After revisiting it more recently, I've realized that your widgets should never really reach extremes like shown above. Extracting out widgets into their own custom reusable classes can clean up your code significantly! Flutter's tooling makes this super easy with "Extract Widget."

Extract Widget
Extract Widget

Test Everywhere and Test Often

This sounds pretty straightforward, but consider it as a reminder. I was tempted to stick with testing on the Flutter Web deploy while writing a bulk of my code because it's easier on my laptop to run a browser than an emulator or dangle a phone from a cable, but even the base material components have quirks on different systems. Something as simple as a scrollbar worked on Android and the web but was not positioned correctly on iOS (see the SafeArea below).

State Management

State management is always a big debate for any framework that doesn't directly set a standard for itself, and Flutter is no different. There are countless helper libraries out there, but getIt is the one that I found to be the most straightforward transitioning from an Angular web environment (for small apps). getIt allows you to set up singleton services that can then inject them throughout your application, similar to how Angular lets you inject singleton services through a component's constructor.

Service registration
Service registration

Once your services are set up, you can then access them anywhere in your application like this:

Accessing a Registered Singleton Service
Accessing a Registered Singleton Service

Use the SafeArea

With phones being released in all different shapes and sizes, it can be difficult to make sure your app will work as expected on all devices. One way to combat some of these issues is with the "SafeArea" widget. I was experiencing some issues with the scrollbar in my application on iOS devices because the calculation for the position was not taking into account the notch (a bug issue has been filed on Github and will be fixed in a future release), but wrapping my widget in a SafeArea resolved the issue. When in doubt, use the SafeArea.

What to Do With JSON

Most services providing data will be serving your app JSON, so we need to know how to handle taking that JSON and creating a strongly typed object. Flutter provides a package for translating JSON using json.decode(object) into a map of strings to dynamic objects. From there, you will want to create a factory that translates that map into a strongly typed object.

JSON Page Factory
JSON Page Factory

In my case, I'm getting my data from Google's Firestore, so I took it one step further to implement a factory that takes a Firestore DocumentSnapshot:

Google Firestore Factory
Google Firestore Factory

One bad habit I brought with me from Typescript and Angular is creating a class (interface) for my JSON object and then a separate widget class for displaying/building the object on the screen. If your object is directly represented by widgets on the screen, you can go ahead and have your strongly typed object coming from JSON extend StatelessWidget!

IDE Extensions for Flutter

You will obviously want/need to install the Dart language service and Flutter extensions, but there are a few other extensions that I've found really helpful while working on flutter.

Bracket Pair Colorizer 2

Bracket Pair Colorizer 2 is beneficial for keeping track of what widget you are nested in. (If you use IntelliJ instead of VSCode, there is a "Rainbow Brackets" plugin that works similarly)

Bracket Pair Colorizer 2
Bracket Pair Colorizer 2

Here are some settings that I use in VSCode to turn down the rainbow explosion. This will match the default VSCode theme pretty closely:

    "bracket-pair-colorizer-2.colors": [],
    "bracket-pair-colorizer-2.scopeLineCSS": [
        "borderStyle : solid",
        "borderWidth : 2px",
        "borderColor : #6e5880",
        "opacity: 1"
    ]
Enter fullscreen mode Exit fullscreen mode

Indent Rainbow

Indent Rainbow accomplishes a similar goal to Bracket Pair Colorizer 2, but it allows you to keep track of your indentation.

Indent Rainbow
Indent Rainbow

This is available in both VSCode and Intellij. Here are some settings again to turn down the rainbows. I use opacity here, which should help this look pretty nice with most themes.

    "indentRainbow.colors": [
        "rgba(50,50,50,1.00)",
        "rgba(50,50,50,0.75)",
        "rgba(50,50,50,0.50)",
        "rgba(50,50,50,0.25)",
        "rgba(50,50,50,0.00)"
    ],
Enter fullscreen mode Exit fullscreen mode

Indented Block Highlighting

This is a recurring theme here, but this is another extension to help you keep track of what widget you are working in. This one will highlight the scope of the current code block. (I'm not sure there is an equivalent for IntelliJ on this one, but I think you can accomplish something similar with settings)

Indented Block Highlighting
Indented Block Highlighting

Google's Flutter Framework

Overall I'm very impressed with how far Flutter has come. After spending 30+ days working on an app sparingly after hours, as an Angular developer, I could pick it up and be effective quickly. Hopefully, you found some of these tips helpful, and follow for more!

Discussion (3)

Collapse
pablonax profile image
Pablo Discobar

If you are interested in this, you can also look at my article about Flutter templates. I made it easier for you and compared the free and paid Flutter templates. I'm sure you'll find something useful there, too. - dev.to/pablonax/free-vs-paid-flutt...

Collapse
chektek profile image
Zack Hoherchak Author

Shout out to "Moussenger" from Reddit, who wanted me to mention that GetIt is really only meant to be used as a way to inject services and is not a fully feature state management library. If you need something more than passing a value or two from one side of the app to the other you will want to invest in a true state management library like Provider, BLoC, Riverpod, Mobx, Redux, etc.

Some comments have been hidden by the post's author - find out more