Top 7 Dart tips and tricks for cleaner Flutter apps

Tags: flutter, dart, android, apps
Published: 2021-02-08 22:55:04

[Dart](https://www.educative.io/blog/dart-2-language-features) is a client-optimized programming language for quickly building mobile, desktop, and server apps. Dart was developed by Google to be used with their cross-platform [Flutter framework](https://www.educative.io/blog/flutter-tutorial). With Flutter and Dart, you can build apps that with slick UI and a native feel. 

Today, we offer our top 7 Dart tips that will help you improve your app development. You can use these tips to write concise code and make the most of the many features that Dart has to offer.

**Tips and tricks at a glance:**
1. [Use anonymous functions as arguments](#1)
2. [Use the `call` method to make classes callable like a function](#2)
3. [Use `.entries` to iterate through a map](#3)
4. [How to use Getters and Setters](#4)
5. [Use a Set for a collection of unique items](#5)
6. [Make use of the Inspect Widget](#6)
7. [Use Sync and Async Generators](#7)
8. [Next steps for your learning](#next)

<a name="1"></a>


## 1. Use anonymous functions as arguments

In the Dart language, functions can be passed as arguments to other functions. Dart provides **anonymous functions** that do not need a name and can be used directly.

Below is an example of an anonymous function in Dart. Here, we pass an anonymous cube function to a built-in method `forEach`. We are trying to  get the cube for every item in a list.

```dart
main() {
  var list = [1,2,3];
  list.forEach((item) {
   print(item*item*item);
  });
}
```

We can also pass anonymous functions as a arguments to other functions. This approach to your code is useful when you use functional operators (like `map`, `reduce`, or `where`).

Below is an example where we define an anonymous function and assign it to a variable. 

```dart
void main() {
  final sayHello = (name) => 'Hey, $name';
  intro(sayHello, 'Amanda');
}

void intro(String Function(String) greet,
             String name) {
  print(greet(name));
  print('Build cool Flutter apps');
}
```


`sayHello` is passed to the `intro` function, which takes the Function argument. On line 6, `String Function(String)` is a function type that returns a string from a given string argument. The anonymous function we use has the same signature, so it is passed as an argument.

<br>

<a name="2"></a>

<br>
## 2. Use the `call` method to make classes callable like a function 


With Dart, you can create a callable class that allows that class instance to be called as a function. We do this with the  `call()` method. See the syntax below. 

```dart
class class_name {
  ... // class 
  
  return_type call ( parameters ) {
    ... // call the function content
  }
  
}
```

Let's see this in action with an example. 

```dart
class EducativeIntro { 
    
  // Defining call method 
  String call(String a, String b, String c) => 'Welcome to $a$b$c'; 
} 
  
// Main Function 
void main() { 
  var educative_input = EducativeIntro(); 
    
  // Calling the class through its instance 
  var educative_output = educative_input('our ', 'Dart ', 'tutorial'); 
    
  print(educative_output); 
}
```



<a name="3"></a>

<br>
## 3. Use `.entries` to iterate through a map

In Dart, you can iterate through a map in a null-safe manner? using `entries`. Say we have a map that tracks the amount of money spent on different products. Typically, we'd iterate through this map with the `!` operator. 

```dart
for (var key in moneySpent.keys) {
  final value = moneySpent[key]!;
  print('$key: $value');
}
```

We can **improve** this code and make it more null-safe using a loop. When we iterate with the `entires` variable, we can access our key-value pairs in a null-safe manner.

```dart
for (var entry in moneySpent.entries) {
  // do something with keys and values
  print('${entry.key}: ${entry.value}');
}
```


<a name="4"></a>

<br>
## 4. How to use Getters and Setters

Getters and setters are special methods that provide read and write access to an object’s properties. Getters and setters are called similar to instance variables: a dot operator (`.`) simply followed by the function name.

Getters are functions that are used to **retrieve the values** of an object’s properties. We use the `get` keyword.

Below is an example where we create a getter function on line 13 that will return the value of name of the current instance. On line 21, we call the getter function and the output should display `Sarah`.


```dart
class Person{
  String name; 
  String gender; 
  int age; 
  
  Person(this.name, this.gender, this.age);

  Person.newBorn(){
    this.age = 0;
  }

  // Getter function getting the value of name
  String get personName => name;

  walking() => print('$name is walking');
  talking() => print('$name is talking');
}

int main() {
  var firstPerson = Person("Sarah","Female",25);
  print(firstPerson.personName);
}
```

Setters are functions that are used to write the **values of an object’s properties**. We use the `set` keyword.

```dart
class Person{
  String name; 
  String gender; 
  int age; 

  String get personName => name;

  // Setter function for setting the value of age
  void set personAge(num val){
    if(val < 0){
      print("Age cannot be negative");
    } else {
      this.age = val;
    }
  } 

  walking() => print('$name is walking');
  talking() => print('$name is talking');
}

int main() {
  var firstPerson = Person();
  firstPerson.personAge = -5;
  print(firstPerson.age);
}
```

From line 9 to line 15, we create a setter function that sets the value for `age`. We also give it a condition so that we cannot input a negative age. And on line 23, we set the value of age for `firstPerson` using the `personAge` setter function.


<a name="5"></a>

<br>
## 5. Use a Set for a collection of unique items

A list is one of the most common collection types in Dart, but lists can hold duplicate items. Sometimes, we want only a collection of unique values. This is where a `Set` is useful.

```dart
final countriesSet = {
  'USA',
  'India',
  'Iceland',
  'USA', 
};
```

In a Set, two elements **cannot be equal**, so the code above will offer a warning and it won't compile. This is also true if we use `const set`.



<a name="6"></a>

<br>
## 6. Make use of the Inspect Widget

In web development, it's common to use the Inspect element, which will tell you all the properties applied to an HTML tag. Dart provides a similar feature called the Inspect Widget that can make app development with Flutter easier. The Flutter Widget Inspector can be used to locate any widget on the screen and view the properties applied to it. 

The inspector can also help you visualize Flutter widget trees to understand layouts or identify layout issues 

To use it, follow these steps:
* Click on the *Flutter inspector*
* Click on the *Enable Select Widget Mode*
* Select a widget on the screen to get more information on it

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/izb28vsr6zmovzxp0cho.png)
 

<a name="7"></a>

<br>

## 7. Use Sync and Async Generators

In Dart, generators make it possible to produce a sequence of values. There are two generator functions:
* **Synchronous Generator:** returns an iterable object
* **Asynchronous Generator:** returns a Stream object

In other words, the synchronous generator returns a collection of values that can be accessed sequentially. We do this by marking the function body as `sync*`. Then, we use *yield statements* for the values.

```dart
Iterable<int> count(int n) sync* {
  for (var i = 1; i <= n; i++) {
    yield i;
  }
}
```

The asynchronous generator, on the other hand, returns a Stream object. A Stream makes it possible to receive a sequence of events. We do this by marking the function body as `async*`. Then, we use use yield statements for the values. 

```dart
Stream<int> countStream(int n) async* {
  for (var i = 1; i <= n; i++) {
    yield i;
  }
}
```


<a name="next"></a>

<br>
## Next steps for your learning

We hope these tips help you make the most of Dart and all the features it offers. Flutter and Dart are a powerful pair for building apps that feel native and slick. Other advanced Dart tools to investigate next are:
* Spread operators for nested if-statements
* Named constructors and initializer lists
* Dart libraries
* Enumerated types 

To get hands-on practice with Dart and learn what new features it offers, check out Educative course **[Developing Web Applications with Dart.](https://www.educative.io/courses/developing-web-applications-with-dart)** You will dive deep into Dart 2 language features and become confident with Dart extensions, enums, mixins, generics, libraries, and more.

*Happy learning!*


<br>
### Continue learning about Dart and app development
* [Flutter Tutorial: the beginner's guide to cross-platform apps](https://www.educative.io/blog/flutter-tutorial)
* [Introducing Dart 2 language features: mixins, enums, and more](https://www.educative.io/blog/dart-2-language-features)
* [Android Tutorial: How to Develop an Android App](https://www.educative.io/blog/how-to-develop-an-android-app)