Почему setState делает закрытие?

Какая польза от setState() принять функцию, чтобы сразу ее вызвать, а затем запросить перестройку? В частности, какое преимущество перед тем, чтобы пользователи явно вызывали функцию типа "перестроить"?

Ответ 1

Когда у Flutter была функция markNeedsBuild, разработчики в конечном итоге просто вызывали ее в случайное время. Когда синтаксис переключился на setState(() {... }), разработчики гораздо чаще использовали API правильно. Они функционально эквивалентны с машинной точки зрения, но, похоже, вызывают другой код у разработчиков.

Если вы будете следовать соглашению только о мутирующих переменных-членах внутри замыкания setState, вы избежите ситуации, когда вы рефакторинуете некоторый код, и случайно удалите вызов setState или setState без необходимости. И если ваше State не установлено, Flutter может не подтвердить утверждение, поэтому вы знаете, что что-то не так, как только вы начинаете пытаться мутировать участников, а не в конце.

В конце концов, вероятно, будет setState предупреждение анализатора, setState что setState всегда вызывается при мутировании членов State, поэтому любая мутация переменной-члена, которая происходит вне initState или обратного вызова setState будет помечена как подозрительная.

Если вы только начинаете работать с состоянием во Flutter, посмотрите тур по виджетам Flutter. Я обнаружил, что во многих случаях, когда я вызывал setState можно более элегантно обрабатывать с помощью FutureBuilder, StreamBuilder, AnimatedWidget или AnimatedBuilder, поэтому не забудьте рассмотреть эти альтернативы, если вы setState вызываете setState.

Адам Барт и Ярослав Волович внесли свой вклад в этот вопрос/ответ.

Ответ 2

Чтобы завершить ответ Колина, он также гарантирует, что вы setState в нужный момент при работе с асинхронной функцией.

Изменение вашего состояния за пределами обратного вызова может привести к простой ошибке:

function() async {
  setState(() {});
  myState = await future;
}

Это вызывает проблему, потому что если ваше будущее не закончится синхронно, метод сборки будет вызван до того, как состояние будет изменено.

Используя обратный вызов, вы вынуждены сделать следующее:

function() async {
  final value = await future;
  setState(() {
    myState = value;
  });
}

На этот раз это не вызывает проблем, потому что будущее ожидается до setState.

Я не могу сделать асинхронный обратный вызов и все еще иметь проблему?

Нет. Потому что метод setState внутренне проверяет, что обратный вызов не возвращает будущее. И если это произойдет, он бросит.

Поэтому следующее невозможно:

setState(() async {
  myState = await future;
});