flutter go_router 不必要的重建在推送和返回时

huangapple go评论77阅读模式
英文:

flutter go_router unnecessary rebuild on push and go back

问题

以下是要翻译的内容:

这是一个测试应用的示例:dartpad

在应用程序内,我们有两个主要路由:ListPageListItemViewScreen
ListItemViewScreen 是从 ListPage 派生的子路由。
在这种情况下,ShellRoute 仅用于示例

问题: 当我们点击列表中的任何项目(第81行 - 推),ListPage 会重建并调用 _loadData() 函数。当我们从 ListItemViewScreen 返回时,ListPage 也会重新构建。

如何防止这种不必要的重建?

英文:

Here is example of test app: dartpad

Inside app we have 2 main routes: ListPage and ListItemViewScreen.
ListItemViewScreen is child route from ListPage.
In this case, ShellRoute used only for example

Problem: when we click on any item in list(row 81 - push), ListPage rebuild and _loadData() function is called. And when we go back from ListItemViewScreen, ListPage rebuild too.

How to prevent this unnecessary rebuild?

答案1

得分: 2

这是因为您实际上在build方法内部调用了函数_loadData()。这通常是一个不好的做法。

相反,将小部件转换为StatefulWidget,设置一个成员来保存未来,然后在initState中为其分配值,并在FutureBuilder中使用该成员作为future(请参见_loadDataFuture):

class ListPage extends StatefulWidget {
  final String type;
  const ListPage({Key? key, required this.type}) : super(key: key);

  @override
  State<ListPage> createState() => _ListPageState();
}

class _ListPageState extends State<ListPage> {
  late final Future<int> _loadDataFuture;
  
  Future<int> _loadData() {
    print("Emulate load data from DB: ${widget.type}");
    return Future.value(1);
  }
  
  @override
  void initState() {
    super.initState();
    _loadDataFuture = _loadData();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _loadDataFuture,
      builder: (context, snapshot) => ListView.builder(
        itemCount: 100,
        itemBuilder: (context, index) {
          return InkWell(
            onTap: () {
              context.push("/list/${widget.type}/view/$index");
            },
            child: Padding(
              padding: const EdgeInsets.all(20),
              child: Text("item_$index"),
            ),
          );
        },
      ),
    );
  }
}

在某些情况下,您可能希望在完成后重新执行未来。在这种情况下,从_loadDataFutre的声明中删除final,如果要触发重新加载,可以使用:

setState(() {
  _loadDataFuture = _loadData();
});
英文:

This happens because you actually call the function _loadData() within the build method. This is generally a bad practice.

Instead, convert the widget into a StatefulWidget, set up a member that will hold the future, assign value to it in initState, and use this member in the FutureBuilder as future (see _loadDataFuture):

class ListPage extends StatefulWidget {
  final String type;
  const ListPage({Key? key, required this.type}) : super(key: key);

  @override
  State&lt;ListPage&gt; createState() =&gt; _ListPageState();
}

class _ListPageState extends State&lt;ListPage&gt; {
  late final Future&lt;int&gt; _loadDataFuture;
  
  Future&lt;int&gt; _loadData() {
    print(&quot;Emulate load data from DB: ${widget.type}&quot;);
    return Future.value(1);
  }
  
  @override
  void initState() {
    super.initState();
    _loadDataFuture = _loadData();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _loadDataFuture,
      builder: (context, snapshot) =&gt; ListView.builder(
        itemCount: 100,
        itemBuilder: (context, index) {
          return InkWell(
            onTap: () {
              context.push(&quot;/list/${widget.type}/view/$index&quot;);
            },
            child: Padding(
              padding: const EdgeInsets.all(20),
              child: Text(&quot;item_$index&quot;),
            ),
          );
        },
      ),
    );
  }
}

It is possible that at some point you do want to re-execute the future after it is completed. In the case, remove the final from the declaration of _loadDataFutre, and if you'd like to trigger a reload, use:

setState(() {
  _loadDataFuture = _loadData();
});

huangapple
  • 本文由 发表于 2023年3月3日 18:21:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/75625825.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定