Корпус строительных лесов перестраивается при открытии меню ящика.

У меня есть виджет с отслеживанием состояния, который строит эшафот. Я использую ящик в эшафоте для бокового меню. Кроме того, тело Scaffold - это FutureBuilder, который получает данные из базы данных firestore и отображает информацию в Card в теле. Кажется, возникла проблема при открытии ящика, из-за которой тело перестраивается, и FutureBuilder снова запрашивает данные. Это снова происходит снова, когда выдвигается ящик. У меня есть другие кнопки в Scaffold на панели приложений и в bottomNavigationBar для перехода к разным маршрутам. При перемещении по этим маршрутам тело не восстанавливается. Может ли кто-нибудь помочь, почему это происходит с ящиком?

Ниже приведен фрагмент кода.

благодаря

class CustomScaffoldState extends State<CustomScaffold> {

Widget build(BuildContext context) {

  return Scaffold(
    drawer: sideMenu(widget.username),

    body: FutureBuilder(
          future: getData(),
          builder: (context, snapshot) {
             if (snapshot.connectionState == ConnectionState.done) {
                 //return the Card with Info
               }
             if (snapshot.hasError) {
                print('Error');
                 }
             else{
                //return a CircularProgressIndicator
                 }
            }
           ));

//appbar and bottomNavigation bar also implemented
}
}

1 ответ

Решение

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

Метод сборки разработан таким образом, что он должен быть чистым / без побочных эффектов. Это связано с тем, что многие внешние факторы могут запускать сборку нового виджета, например:

Маршрут pop / push Изменение размера экрана, обычно из-за внешнего вида клавиатуры или изменения ориентации Родительский виджет воссоздал свой дочерний виджет InheritedWidget, от которого зависит виджет (шаблон Class.of(context)). Это означает, что метод сборки не должен запускать HTTP-вызов или изменять любое состояние.

Как это связано с вопросом?

Проблема, с которой вы столкнулись, заключается в том, что ваш метод сборки имеет побочные эффекты / не является чистым, что затрудняет посторонний вызов сборки.

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

В случае вашего примера вы должны преобразовать свой виджет в StatefulWidget, а затем извлечь этот HTTP-вызов в initState вашего состояния:

class Example extends StatefulWidget {
  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  Future<int> future;

  @override
  void initState() {
    future = Future.value(42);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: future,
      builder: (context, snapshot) {
        // create some layout here
      },
    );
  }
}

Я это уже знаю. Я пришел сюда, потому что очень хочу оптимизировать перестроения

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

Когда экземпляр виджета остается прежним; Flutter намеренно не восстанавливает детей. Это означает, что вы можете кэшировать части своего дерева виджетов, чтобы предотвратить ненужные перестроения.

Самый простой способ - использовать конструкторы dart const:

@override
Widget build(BuildContext context) {
  return const DecoratedBox(
    decoration: BoxDecoration(),
    child: Text("Hello World"),
  );
}

Благодаря этому ключевому слову const экземпляр DecoratedBox останется прежним, даже если сборка вызывалась сотни раз.

Но вы можете добиться того же результата вручную:

@override
Widget build(BuildContext context) {
  final subtree = MyWidget(
    child: Text("Hello World")
  );

  return StreamBuilder<String>(
    stream: stream,
    initialData: "Foo",
    builder: (context, snapshot) {
      return Column(
        children: <Widget>[
          Text(snapshot.data),
          subtree,
        ],
      );
    },
  );
}

В этом примере, когда StreamBuilder получает уведомление о новых значениях, поддерево не будет перестраиваться, даже если StreamBuilder/Column это сделает. Это происходит потому, что из-за закрытия экземпляр MyWidget не изменился.

Этот паттерн часто используется в анимации. Типичное использование - AnimatedBuilder и все переходы, такие как AlignTransition.

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

Другие вопросы по тегам