一尘不染

如何处理不需要的小部件构建?

flutter

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

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

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

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

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


阅读 329

收藏
2020-08-13

共1个答案

一尘不染

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

  • 路线弹出/推入
  • 屏幕尺寸调整,通常是由于键盘外观或方向改变
  • 父小部件重新创建了它的子级
  • 小部件所依赖的InheritedWidget(Class.of(context)模式更改)

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


这与问题有什么关系?

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

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

在您的例子中,你会改变你的工具到一个StatefulWidget然后解压缩HTTP调用initState你的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
      },
    );
  }
}

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

也有可能使小部件能够重建而无需强迫其子代进行构建。

当窗口小部件的实例保持不变时;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收到新值的通知时,subtree即使StreamBuilder /
Column这样做也不会重建。发生这种情况的原因是,由于有了闭包,的实例MyWidget没有改变。

动画中经常使用这种模式。通常的用途是AnimatedBuilder和所有过渡,例如AlignTransition

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

2020-08-13