Flutter Best Practices

Naming convention

  1. 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 a new 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 include Text, Padding, and Icons, 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';
    },
  ));
}
0
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.