打开“抽屉"菜单时,将重建脚手架的主体 [英] Body of a Scaffold is rebuilt when opening a Drawer menu

查看:66
本文介绍了打开“抽屉"菜单时,将重建脚手架的主体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个有状态的小部件,可以构建一个脚手架.我正在使用脚手架中的抽屉作为侧面菜单.另外,支架的主体是FutureBuilder,它从Firestore数据库获取数据并在主体的Card中显示信息.打开抽屉时似乎出现问题,这将导致车身重建,并且FutureBuilder中的future再次查询数据.弹出抽屉时再次发生这种情况.我在appbar和bottomNavigationBar的Scaffold中都有其他按钮,可以导航到不同的路线.在导航这些路线时不会重建车身.任何人都可以帮助我解释为什么抽屉会发生这种情况?

I have a Stateful widget which builds a Scaffold. I am using a drawer in the Scaffold for a side menu. Also, the body of the Scaffold is a FutureBuilder which gets data from firestore database and displays the info in a Card in the body. There seems to be an issue while opening a drawer which causes the body to be rebuilt and the future in the FutureBuilder queries the data again. This happens again again when the drawer is popped. I have other buttons in the Scaffold in both appbar and bottomNavigationBar to navigate to different routes. The body isn't being rebuilt while navigating these routes. Could anyone please help as to why is it happening with the Drawer?

下面是代码片段.

谢谢

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
}
}

推荐答案

当抽屉或软键盘打开屏幕更改状态时,有时构建方法会自动重新加载,请检查

When the drawer or soft keyboard opened the state of the screen change and sometimes the build method reload automatically, please check this link for more information.

构建方法的设计方式应使其纯净/无副作用.这是因为许多外部因素都可以触发新的小部件构建,例如:

The build method is designed in such a way that it should be pure/without side effects. This is because many external factors can trigger a new widget build, such as:

弹出/下推路线屏幕尺寸调整,通常是由于键盘外观或方向改变父小部件重新创建了它的子级小部件依赖于(Class.of(context)模式)更改的InheritedWidget这意味着build方法不应触发http调用或修改任何状态.

Route pop/push Screen resize, usually due to keyboard appearance or orientation change Parent widget recreated its child An InheritedWidget the widget depends on (Class.of(context) pattern) change This means that the build method should not trigger an http call or modify any state.

这与问题有什么关系?

您面临的问题是您的构建方法有副作用/不是很纯正,这使多余的构建调用变得很麻烦.

The problem you are facing is that your build method has side-effects/is not pure, making extraneous build call troublesome.

您应该使构建方法纯净,而不是阻止构建调用,以便可以在没有影响的情况下随时调用它.

Instead of preventing build call, you should make your build method pure, so that it can be called anytime without impact.

在您的示例中,您将小部件转换为StatefulWidget,然后将该HTTP调用提取到您所在州的initState:

In the case of your example, you'd transform your widget into a StatefulWidget then extract that HTTP call to the initState of your State:

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
      },
    );
  }
}

我已经知道了.我来这里是因为我真的想优化重建

I know this already. I came here because I really want to optimize rebuilds

还可以使小部件能够重建而无需强迫其子代进行构建.

It is also possible to make a widget capable of rebuilding without forcing its children to build too.

小部件的实例保持不变时;Flutter故意不会重建孩子.这意味着您可以缓存小部件树的一部分,以防止不必要的重建.

When the instance of a widget stays the same; Flutter purposefully won't rebuild children. It implies that you can cache parts of your widget tree to prevent unnecessary rebuilds.

最简单的方法是使用dart const构造函数:

The easiest way is to use dart const constructors:

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

由于使用了const关键字,即使构建被调用了数百次,DecoratedBox的实例也将保持不变.

Thanks to that const keyword, the instance of DecoratedBox will stay the same even if build were called hundreds of times.

但是您可以手动获得相同的结果:

But you can achieve the same result manually:

@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的实例没有更改.

In this example when StreamBuilder is notified of new values, subtree won't rebuild even if the StreamBuilder/Column do. It happens because, thanks to the closure, the instance of MyWidget didn't change.

此模式在动画中使用很多.典型用途是AnimatedBuilder和所有过渡,例如AlignTransition.

This pattern is used a lot in animations. Typical uses are AnimatedBuilder and all transitions such as AlignTransition.

您也可以将子树存储到类的字段中,尽管不建议这样做,因为它会破坏热重载功能.

You could also store subtree into a field of your class, although less recommended as it breaks the hot-reload feature.

这篇关于打开“抽屉"菜单时,将重建脚手架的主体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆