Flutter Best Practices


Naming convention
- Classes, enums, typedefs, and extensions name should be in
UpperCamelCase.
2. Libraries, packages, directories, and source files name should be in snake_case(lowercase_with_underscores).
library firebase_dynamic_links;
import ‘socket/socket_manager.dart’;
3. Variables, constants, parameters, and named parameters should be in lowerCamelCase.
var item;
const testValue= 14.28;
final urlScheme = RegExp(‘^([a-z]+):’);
void sum(int testValue) { // …}
Strings
1 . PREFER using interpolation to compose strings and values.
Generally, we are used to using long chains of +
to build a string out of literals and other values. That does work in Dart, but it’s almost always cleaner and shorter to use interpolation:
'Hello, $name! You are ${year - birth} years old.';
2 . AVOID using curly braces in interpolation when not needed.
If you’re interpolating a simple identifier not immediately followed by more alphanumeric text, the {}
should be omitted.
'Hi, $name!'
"Wear your wildest $decade's outfit."
Specify types for class member
Always specify the type of member when it’s value type is known. Avoid using var
when possible.
int item = 10;
final User user = User();
String name = ‘pooja’;
const int timeOut = 20;
DON’T use new
Dart 2 makes the
new
keyword optional. Even in Dart 1, its meaning was never clear because factory constructors mean anew
invocation may still not actually return a new object.The language still permits
new
in order to make migration less painful, but consider it deprecated and remove it from your code.
//Do
Widget build(BuildContext context) {
return Row(
children: [
RaisedButton(
child: Text('Increment'),
),
Text('Click!'),
],
);
}//Don'tWidget build(BuildContext context) {
return new Row(
children: [
new RaisedButton(
child: new Text('Increment'),
),
new Text('Click!'),
],
);
}
Use if
condition instead of conditional expression
Many times we need to render a widget based on some condition in Row and Column. If conditional expression return null in any case then we should use the if condition only.
//Don't
Widget getText(BuildContext context) {
return Row(
children: [
Text("Hello"),
Platform.isAndroid ? Text("Android") : null,
Platform.isAndroid ? Text("Android") : SizeBox(),
Platform.isAndroid ? Text("Android") : Container(),
]
);
}
//Do
Widget getText(BuildContext context) {
return Row(
children:
[
Text("Hello"),
if (Platform.isAndroid) Text("Android")
]
);
}
Use Cascades Operator
It allows you to perform a sequence of operations on the same object. It saves your number of steps and needs for a temporary variable.
Demo d1 = new Demo();
Demo d2 = new Demo();// Without Cascade Notation
d1.setA(20);
d2.setB(30);
d1.showVal();// With Cascade Notation
d2..setA(10)
..setB(15)
..showVal();
Use expression function bodies
For functions that contain just one expression, you can use an expression function. The =>
(arrow) notation is used for expression function.
num get x => center.x;
set x(num value) => center = Point(value, center.y);
Avoid large trees, split your code into small widgets instead
*Dividing your code into small reusable widgets not only promotes its reusability but also it's readability too.*
In the example below, EventItem
is a separate widget that will load individual events. EventItem
is usually stored in a separate file.
itemBuilder: (ctx, i) => ChangeNotifierProvider.value(
value: events[i],
child: EventItem(),
),
Utilities
Placing reusable functions in a class, so it's easy to access them. Also, For Dialog components, if you are using a package to wrap their logic with your own custom widget, so it would be easy to change the package if necessary later.
Const Widgets
Whenever you have widgets that don’t change when the state changes, you should declare them as constants. This will prevent them from being rebuilt, hence improving performance.
This is similar to caching widgets that won’t get rebuilt. Some of the widgets that can be declared as
const
includeText
,Padding
, andIcons
, to mention a few. If the widgets contain dynamic information, they shouldn’t be declared as constants.
Remove Unused Resources
Especially when you’re ready to publish your application, you’ll need to remove resources that you aren’t using in your application. These could be image assets, for example. Removing unused resources and compressing images will help you reduce the size of your application.
Use Trailing Commas
Since your widget tree can grow quickly, you need a way to format your code in a way that makes it easy to read. Adding trailing commas and using your IDE’s formatting shortcuts leads to more readablility.
Render Grids and Lists Lazily
Use the lazy methods, with callbacks, when building large grids or lists. That way only the visible portion of the screen is built at startup time.
Some ways to lazy load data
- FutureBuilder
- lazy_load_scrollview package
Flutter Analyze
*It’s important to check the code with the analyzer. Run flutter analyze
in your terminal to check your code. This tool is a wrapper around the [dartanalyzer](https://www.dartlang.org/tools/analyzer) tool. It performs static analysis of your code.*
flutter analyzeAnalyzing test-flutter...
info • ‘WhitelistingTextInputFormatter’ is deprecated and shouldn’t be used. Use FilteringTextInputFormatter.allow instead. This feature was deprecated after
v1.20.0–1.0.pre. • lib/common_widgets/text_fields.dart:86:23 • deprecated_member_use
info • ‘WhitelistingTextInputFormatter’ is deprecated and shouldn’t be used. Use FilteringTextInputFormatter.allow instead. This feature was deprecated after
v1.20.0–1.0.pre. • lib/common_widgets/text_fields.dart:348:21 • deprecated_member_use
Flutter Pub Version Checker (Android Studio Plugin)
Plugin for checking the latest Pub packages versions. It will automatically run inspection in your pubspec.yaml file to check all dependencies and compare versions with the latest versions from the Pub package repository. The highlighted ones need an update.
pubspec.yaml
Maintain hard-coded values, strings, colors in a separate file
Create a separate dart file to store strings, colors, constants. so it’s easy to access them.
colors.dart
strings.dart
Custom Error Screen: handle “RED SCREEN OF DEATH”
Use ErrorWidget that renders an exception’s message. This widget is used when a build method fails, to help with determining where the problem lies. Exceptions are also logged to the console, which you can read using
flutter logs
. The console will also include additional information such as the stack trace for the exception. It is possible to override this widget*. Refer this [article](https://medium.com/nonstopio/flutter-kill-the-red-screen-of-death-f5e0601d1cdc) to know it in more details.*
import 'package:flutter/material.dart';
void main() {
ErrorWidget.builder = (FlutterErrorDetails details) {
bool inDebug = false;
assert(() { inDebug = true; return true; }());
// In debug mode, use the normal error widget which shows
// the error message:
if (inDebug)
return ErrorWidget(details.exception);
// In release builds, show a yellow-on-blue message instead:
return Container(
alignment: Alignment.center,
child: Text(
'Error!',
style: TextStyle(color: Colors.yellow),
textDirection: TextDirection.ltr,
),
);
};
// Here we would normally runApp() the root widget, but to demonstrate
// the error handling we artificially fail:
return runApp(Builder(
builder: (BuildContext context) {
throw 'oh no, an error';
},
));
}
Subscribe to my newsletter
Read articles from NonStop io Technologies directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

NonStop io Technologies
NonStop io Technologies
Product Development as an Expertise Since 2015 Founded in August 2015, we are a USA-based Bespoke Engineering Studio providing Product Development as an Expertise. With 80+ satisfied clients worldwide, we serve startups and enterprises across San Francisco, Seattle, New York, London, Pune, Bangalore, Tokyo and other prominent technology hubs.