Dart 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. 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:
call
method to make classes callable like a function.entries
to iterate through a mapLearn the new Dart 2 language features. You’ll become confident with extensions, enums, mixins, generics, and more.
Developing Web Applications with Dart
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.
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.
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.
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.
class class_name {... // classreturn_type call ( parameters ) {... // call the function content}}
Let’s see this in action with an example.
class EducativeIntro {// Defining call methodString call(String a, String b, String c) => 'Welcome to $a$b$c';}// Main Functionvoid main() {var educative_input = EducativeIntro();// Calling the class through its instancevar educative_output = educative_input('our ', 'Dart ', 'tutorial');print(educative_output);}
Note: Dart doesn’t support multiple callable methods.
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.
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.
for (var entry in moneySpent.entries) {// do something with keys and valuesprint('${entry.key}: ${entry.value}');}
Learn Dart and its updates without scrubbing through videos or documentation. Educative’s text-based courses are easy to skim and feature live coding environments, making learning quick and efficient.
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
.
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 nameString 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.
class Person{String name;String gender;int age;String get personName => name;// Setter function for setting the value of agevoid 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 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.
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
.
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:
In Dart, generators make it possible to produce a sequence of values. There are two generator functions:
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.
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.
Stream<int> countStream(int n) async* {
for (var i = 1; i <= n; i++) {
yield i;
}
}
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:
To get hands-on practice with Dart and learn what new features it offers, check out Educative course 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!
Free Resources