如何处理不需要的小部件构建? [英] How to deal with unwanted widget build?

查看:77
本文介绍了如何处理不需要的小部件构建?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于各种原因,有时会再次调用我的小部件的build方法.

For various reasons, sometimes the build method of my widgets is called again.

我知道这是因为父母更新了.但这会导致不良影响. 导致问题的典型情况是使用FutureBuilder的这种方式:

I know that it happens because a parent updated. But this causes undesired effects. A typical situation where it causes problems is when using FutureBuilder this way:

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

在此示例中,如果再次调用 build 方法,它将触发另一个HTTP请求.这是不希望的.

In this example, if the build method were to be called again, it would trigger another HTTP request. Which is undesired.

考虑到这一点,如何处理不需要的构建?有什么方法可以防止生成调用吗?

Considering this, how to deal with the unwanted build? Is there any way to prevent a build call?

推荐答案

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

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

这意味着build方法不应触发http调用或修改任何状态.

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调用提取到StateinitState:

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


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

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

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这样做,subtree也不会重建. 发生这种情况的原因是,由于关闭了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.

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

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

这篇关于如何处理不需要的小部件构建?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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