“This article has participated in the call for good writing activities, click to view: the back end, the big front end double track submission, 20,000 yuan prize pool waiting for you to challenge!”

Regardless of the programming language, developers need to work on improving code readability, maintainability, robustness, and so on. Flutter also requires some best practices that allow us to write consistent, robust, fast code that is also easy to read and view. Effective Dart provides a detailed guide, but it’s hard to read and remember. This article lists some of the most common examples based on the experience of long-term development.

Naming rules

  • UpperCamelCaseBig hump nomenclature. Capitalize the first letter of each word.
  • lowerCamelCaseSmall hump nomenclature, first word begins with lower case, other words begin with upper case.
  • lowercase_with_underscoresLowercase underscore nomenclature, all words in lower case, with underscores between words_The connection.
  1. Use small camel name for variables, constants, method names, and parameters. Note that constants are also small camel name:

    String name;
    int phoneNumber = 123456789;
    const songPrice = 9.99;
    void sum(int songPrice){
      //....
    }
    Copy the code
  2. Class names, constructor names, extension class names, definition types, enumerators use big camel names:

    extension MyFancyList<T> on List<T> { ... }
    class Foo {
      const Foo([Object? arg]);
    }
    typedef Predicate<T> = bool Function(T value);
    enum Status {
       none,
       running,
       stopped,
       paused
    }
    Copy the code
  3. Use lowercase underscores for Packages, Libraries, file names, and guide package aliases:

    library peg_parser.source_scanner;
    import 'dart:math' as math;
    import 'package:angular_components/angular_components'
        as angular_components;
        
    Copy the code

Guide packets using relative paths

To avoid the confusing situation where a project uses both relative and absolute paths, use relative paths in folders. Because the IDE is not that smart, changing the folder name or moving the folder will cause errors in the guide path.

// Don't import 'package:demo/src/utils/dialog_utils.dart'; // Do import '.. /.. /.. /utils/dialog_utils.dart';Copy the code

Specifies a type for a variable that may be null without being initialized to null

Dart supports type inference, but to make it easier to read and know the type at a glance, we need to specify the type:

//Don't
var item = 10;
final car = Car();
const timeOut = 2000;


//Do
int item = 10;
final Car bar = Car();
String name = 'john';
const int timeOut = 20;
Copy the code

For nullable types, there is no need to show that they are initialized to null because the default is null:

// Do
String name;

// Don't
String name = null;
Copy the code

Use operators and cascade operators

Use?? Instead of null-checking the expression, shorten the code:

// Do a = x ?? y; // Don't a = x == null ? y : x; // Do a = x? .y; // Don't a = x == null ? null : x.y; // Do List<String>? strs; if (strs? .isNotEmpty ?? false) { //... } // Don't List<String>? strs; if (strs! =null&&strs.isNotEmpty) { //... }Copy the code

Expand list items using the expand operator:

Var y = [4,5,6]; Var x = y] [1, 2,... Var y = [4,5,6]; Var x = [1, 2]; x.addAll(y);Copy the code

If a series of operations are performed on the same object, a cascading expression should be used:

// Do var path = Path() .. lineTo(0, size.height) .. lineTo(size.width, size.height) .. lineTo(size.width, 0) .. close(); // Don't var path = Path(); path.lineTo(0, size.height); path.lineTo(size.width, size.height); path.lineTo(size.width, 0); path.close();Copy the code

Using lambda expressions:

//Do get width => right - left; Widget getProgressBar() => CircularProgressIndicator( valueColor: AlwaysStoppedAnimation<Color>(Colors.blue), ); //Don't get width { return right - left; } Widget getProgressBar() { return CircularProgressIndicator( valueColor: AlwaysStoppedAnimation<Color>(Colors.blue), ); } //------------------------------------------------------------- List<String> names=[] // Do names.forEach(print); // Don't names.forEach((name) {print(name); });Copy the code

By using raw strings, you can avoid escaping backslashes and dollar signs:

//Do
var s = r'This is demo string \ and $';

//Don't
var s = 'This is demo string \\ and \$';
Copy the code

Building strings with interpolation instead of concatenating strings with + makes strings cleaner and shorter.

// Do var description = 'Hello, $name! You are ${year - birth} years old.'; //Don't var description = 'Hello, '+ name + '! You are ' + (year - birth).toString() + ' years old.';Copy the code

Use the operator is to avoid strong conversions, which may throw an exception if the type is inconsistent:

//Do
if (item is Animal){
 item.name = 'Lion';
} 
  
//Don't
(item as Animal).name = 'Lion';
Copy the code

Avoid the use ofprint()

If you print too many logs, Android will discard some of them and print() will leak logs, so use debugPrint(), Dart: Developer: log().

useasync/awaitProcessing asynchronous Tasks

Asynchronous code is difficult to read and debug. Async ‘ ‘await syntax improves readability, avoids hellish callbacks and nesting, and makes asynchronous code look like synchronous code:

// Do Future<int> countActiveUser() async { try { var users = await getActiveUser(); return users? .length ?? 0; } catch (e) { log.error(e); return 0; // Don't Future<int> countActiveUser() {return getActiveUser(). Then ((users) {return users? .length ?? 0; }).catchError((e) { log.error(e); return 0; }); }Copy the code

Nested controls with Const and extract

If the control does not need to change state when calling setState, it needs to be declared Const to avoid rebuilding:

Container(
      padding: const EdgeInsets.only(top: 10),
      color: Colors.black,
      child: const Center(
        child: const Text(
          "No Data found",
          style: const TextStyle(fontSize: 30, fontWeight: FontWeight.w800),
        ),
      ),
    );
Copy the code

If too many nested controls are extracted into separate widgets, do not extract into methods:

The draw method will rebuild, and details from the rendering process illustrate the error that Old Flutter often made — multiple builds

// Do class _NonsenseWidget extends StatelessWidget { const _NonsenseWidget(); @override Widget build(BuildContext context) { return Row( children: < widgets > [Text (' I am the first row), Text (' I am the second line), Text (' I am the third row),],); }} / / Don 't Row _buildRow () {return Row (children: < widgets > [Text (' I am the first Row), Text (' I am the second line), Text (' I am the third Row),],); }Copy the code