delaram
delaram

Reputation: 819

Flutter : Avoid using `forEach` with a function literal

Hi everyone this is my whole method :

Future<void> init() async {
    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loginState = ApplicationLoginState.loggedIn;
        _guestBookSubscription = FirebaseFirestore.instance
            .collection('guestbook')
            .orderBy('timestamp', descending: true)
            .limit(3)
            .snapshots()
            .listen((snapshot) {
          _guestBookMessages = [];
          snapshot.docs.forEach((document) {
            _guestBookMessages.add(
              GuestBookMessage(
                name: document.data()['name'] as String,
                message: document.data()['text'] as String,
              ),
            );
          });
          notifyListeners();
        });
      } else {
        _loginState = ApplicationLoginState.loggedOut;
        _guestBookMessages = [];
        _guestBookSubscription?.cancel();
      }
      notifyListeners();
    });
  }

the part that dart complains about is this one :

snapshot.docs.forEach((document) {
            _guestBookMessages.add(
              GuestBookMessage(
                name: document.data()['name'] as String,
                message: document.data()['text'] as String,
              ),
            );
          });

how can I change this method without ruining the whole functionality ? Im just looking for a way that makes dart happy . I appreciate your help in advance.

Upvotes: 42

Views: 21586

Answers (4)

Mathis Fouques
Mathis Fouques

Reputation: 234

There is a debate below the accepted answer, about readability of the recommended lint rules at stake here. This is the rule in question causing the problem : https://dart.dev/tools/linter-rules/avoid_function_literals_in_foreach_calls

You can disable it by modifying your analysis_options.yaml file :

linter:
  rules:
    avoid_function_literals_in_foreach_calls: false

Upvotes: 3

Sifat Amin
Sifat Amin

Reputation: 1186

AVOID using forEach with a function literal.

AVOID:

snapshot.docs.forEach((document) {
  ...
});

GOOD:

for (var document in snapshot.docs) {
  // Rest of your code
}

Upvotes: 54

Sittiphan Sittisak
Sittiphan Sittisak

Reputation: 885

Using like data.forEach(function); example:

void main() async {
  List<int> list = [1, 2, 3, 4, 5];

  //recommended
  list.forEach(showSquareNumbers);

  //not recommended
  list.forEach((int number) => showSquareNumbers(number));
  list.forEach((int number) {
    showSquareNumbers(number);
  });
}

void showSquareNumbers(int data) {
  print("$data * $data = ${data * data}");
}

This is my opinion.

I think the forEach seems more complicated than the for loop and the forEach can't use continue and break (return is available but not a thing happens when using return).

void test(List data) {
  data.forEach((element) {
    print(element);
    if(element) return;
  });

  for (var element in data) {
    print(element);
    if(element) continue;
    if(element) break;
    if(element) return;
  }
}

I think we should use the for instead of the forEach loop when your forEach loop seems like this code below because the for loop have many options more than forEach as I said.

  data.forEach((element) {
    print(element)
  });
  //or
  data.forEach((element) => print(element));

I think the forEach loop is used for short code (easy to understand) and when you want to do something you don't care about the result like this code (using with Function(dynamic)).

void test(List data) {
  void showInTerminal(e) {
    print("data is $e");
  }
  data.forEach(showInTerminal);
  
  Function(dynamic) function = showInTerminal;
  data.forEach(function);
}

Make sure the data type and function(type) are the same.

//error
void test(List<Map> data) {
  void showInTerminal(String e) {
    print("data is $e");
  }
  data.forEach(showInTerminal);
}

//success
void test(List<Map> data) {
  void showInTerminal(Map e) {
    print("data is $e");
  }
  data.forEach(showInTerminal);
}

I code like this. I think it's easy to read.

void test() {
  dataList.forEach(removeData);
  fileList.forEach(removeFile);
}

Upvotes: 6

iDecode
iDecode

Reputation: 28876

Use await for:

await for (final document in snapshot.docs) {
  // Your code...
}

Upvotes: -5

Related Questions