Восстанавливает ли все поддерево на setState во флаттере - PullRequest
3 голосов
/ 07 мая 2020

Я новичок в флаттере и мне действительно интересно, все ли поддерево виджетов перестраивается, когда мы вызываем setState.

Поддерево здесь означает все дерево виджетов ниже этого виджета (включая этот виджет как узел root).

Когда мы вызываем функцию setState, метод build вызывается для root node поддерева, которое запускает методы сборки для его дочернего элемента. Скажем, ветвь (здесь MyWidget1) поддерева (дочернего элемента этого виджета) не зависит от переменных состояния. Я заметил, что даже независимые ветки перестраиваются на setState, вызываемом в родительском узле.

class _MyAppState extends State<MyApp> {
  int count=0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(children: <Widget>[ MyWidget1(),MyWidget2(count),],),
      floatingActionButton: FloatingActionButton(onPressed: ()=>setState((){count++;}),), 
    );
  }
}

class MyWidget1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) { print("widget builds 1");
    return Container(height: 100, color: Colors.orange,);
  }
}
class MyWidget2 extends StatelessWidget {
  final int count;
  MyWidget2(this.count);
  @override
  Widget build(BuildContext context) { print("widget builds 2");
    return Text(count.toString());
  }
}

Здесь мы видим, что MyWidget1 не зависит от переменной состояния (здесь count), поэтому обычно , setState не должно на него влиять. Мне было интересно, должна ли быть какая-то оптимизация, чтобы избежать этой бесполезной сборки MyWidget1 при вызове функции setState. Поскольку дерево ниже MyWidget1 может быть слишком большим, оно тоже будет перестроено снова.

Мои вопросы:

  1. Это нормально для этого Независимый виджет (здесь MyWidget1) для повторной сборки на setState?

  2. Есть ли лучший способ справиться с этой ситуацией, чтобы избежать его перестройки.

Примечание: я прочитал этот вопрос

В этом вопросе есть способ избежать бесполезной сборки, создав экземпляр независимой ветки вне метода сборки,

Я сомневаюсь:

Это СПОСОБ справиться с этой ситуацией или какой-то другой лучший способ, или эта ситуация совсем не такая уж большая, поскольку дерево строится за O (n) время ( который, я думаю, не должен быть ответом, потому что построение дерева может быть операцией O (n), но оно может включать в себя множество трудоемких операций, которые могут быть не оптимизированы для повторного вызова без толку).

1 Ответ

3 голосов
/ 08 мая 2020

Да, MyWidget1 перестраивается на основе этого setState. Просто доверяйте коду. После вызова setState вызывается build, который вызывает конструктор MyWidget1. После каждого setState все поддерево перестраивается. Выбрасываются старые виджеты. Однако государства не выбрасываются. Экземпляры состояний существуют, они не воссоздаются (см. DidUpdateWidget).

Итак, да. После каждого setState все поддерево перестраивается.

Это нормально, не волнуйтесь.

Классы виджетов здесь очень легкие. Сборщик мусора Dart оптимизирован для создания множества таких объектов и их удаления вместе.

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

К чему все эти неприятности, спросите вы. Потому что создавать деревья легко, а ухаживать за ними сложно. Эта реактивная декларативная структура позволяет нам просто создать дерево, но не поддерживать его.

Есть несколько ресурсов о внутреннем устройстве Flutter, о которых вы можете прочитать больше. Один из таких ресурсов - это видео: https://www.youtube.com/watch?v=996ZgFRENMs

...