StatelessWidget против функции, возвращающей виджеты с точки зрения производительности
Есть ли разница в производительности при использовании StatelessWidget
против function returning a Widget
?
Я хорошо знаю, по крайней мере, различия, указанные в проблеме репо этого флаттера, которые не связаны с производительностью.
Дело в том, что у меня есть коллеги, утверждающие, что functional widgets
худшие с точки зрения производительности, но после прочтения немного о предмете я не могу найти какой-либо убедительной части документации, которая могла бы подтвердить это утверждение, поэтому любые разъяснения по этому вопросу будут очень приветствоваться!
Насколько я вижу, единственное различие между ними было бы в случае использования const Widget
Кажется, что это позволит избежать этапа восстановления.
1 ответ
Прежде всего, я хотел бы отметить, что пакет доступен для StatelessWidget
из функции: functions_widget
Выигрыш в производительности не обязательно соответствует действительности. Это зависит от того, как вы используете свои виджеты, в основном от того, как вы используете их для управления своим состоянием.
По умолчанию классы могут ухудшать производительность, в отличие от функций в приложении, которое не использует их мощность.
Реальный вопрос: в чем их сила?
Просто: классы могут обновляться независимо друг от друга. Функции не могут
Классы могут частично обновлять дерево виджетов.
Рассмотрим виджет, который перестраивает каждый кадр и возвращает его дочерний элемент:
class InfiniteLoop extends StatefulWidget {
const InfiniteLoop({Key key, this.child}) : super(key: key);
final Widget child;
@override
_InfiniteLoopState createState() => _InfiniteLoopState();
}
class _InfiniteLoopState extends State<InfiniteLoop> {
@override
Widget build(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {}));
return widget.child;
}
}
Что будет, если мы поместим все наше приложение в этот виджет?
void main() => runApp(InfiniteLoop(child: MyApp()));
Ничего такого
Конечно, у вас будет один виджет, который часто перестраивается в вашем дереве. Но на самом деле build
метод MyApp
будет вызван только один раз.
Это потому, что Flutter может прервать перестроение дерева, когда экземпляр виджета не изменяется.
Классы могут злоупотреблять этой оптимизацией.
Используя классы, можно разумно разделить перестройку дерева виджетов на независимые части.
Нецелесообразно перечислять все потенциальные факторы оптимизации, которые допускает класс, так как их слишком много.
В следующем примере приведен виджет, который принимает int
и форматирует его в Text
, Уловка в том, что этот виджет будет перестраиваться только если int
прошло изменение:
class Counter extends StatelessWidget {
const Counter({Key key, this.value}) : super(key: key);
final int value;
@override
Widget build(BuildContext context) {
return Text(value.toString());
}
@override
bool operator ==(Object other) =>
identical(this, other) || (other is Counter && other.value == value);
@override
int get hashCode => value.hashCode;
}
Это работает, потому что Flutter использует ==
Оператор, чтобы узнать, должен ли виджет обновляться или нет (следовательно, почему const
конструктор является хорошим фактором оптимизации).
Это не единственное решение, но это хороший пример того, что функции не могут сделать.