【问题标题】:Widget continuously being reloaded小部件不断被重新加载
【发布时间】:2020-08-12 14:51:00
【问题描述】:

请查看此36 seconds 视频以获得更清晰的信息,因为它解释的内容过于冗长:https://www.youtube.com/watch?v=W6WdQuLjrCs

我的最佳猜测

  • 这要归功于提供商。

应用结构 ->

Outer Page -> NoteList Page

外页代码:


class OuterPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return OuterPageState();
  }
}

class OuterPageState extends State<OuterPage> {
  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
  int _selectedTab = 0;
  var noteList;
  final _pageOptions = [
    NoteList(),
    AnotherPageScreen(),
  ];

  @override
  Widget build(BuildContext context) {
    var noteProvider = Provider.of<NotesProvider>(context, listen: false);
    var customFabButton;
    if (_selectedTab == 0) {
      customFabButton = FloatingActionButton(
        // Password section
        onPressed: () {
          navigateToDetail(context, Note('', '', 2), 'Add Note');
        },
        child: Icon(Icons.add),
      );
~~~ SNIP ~~~

Notes 选项卡又名NoteList 页面代码:

class NoteList extends StatefulWidget {
  NoteList();

  @override
  NoteListState createState() => NoteListState();
}

class NoteListState extends State<NoteList> {
  final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
  List<Note> noteList;
  int count = 0;

  @override
  Widget build(BuildContext context) {
    Provider.of<NotesProvider>(context).getNotes();
    return Scaffold(
        key: _scaffoldKey,
        body: Provider.of<NotesProvider>(context).count > 0
            ? NoteListScreen(_scaffoldKey)
            : CircularProgressIndicator());
  }
}

完整代码:查看这里:https://github.com/LuD1161/notes_app/tree/reusable_components

更新 1 - 可能的解决方案是 FutureBuilder

我知道FutureBuilder 有一个可能的解决方案,但我认为即使Provider 也适合这个用例。

而且这里是反模式吗?

另外,请不要为同一事物推荐其他软件包,如果可能,请尝试将解决方案限制为 Provider 或基础库。

更新 2 - FutureBuilder 无法实现

FutureBuilder 不能在此处使用,因为list tile 中有一个delete 按钮,因此当笔记被删除时,note list 将不会更新。

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    问题是由于您从 build 方法调用的 getNotes 函数。您正在从该函数调用 notifyListeners 。它再次重新构建小部件并再次调用构建方法并继续此循环。

    您需要将提供程序的侦听属性设置为 false,但这会破坏您的功能。要解决此问题,您必须将 getNotes 调用从 build 函数移动到 initState,如下所示:

    @override
    void initState() {
      super.initState();
      postInit(() {
        Provider.of<NotesProvider>(context).getNotes();
      });
    }
    

    实现 postInit(参考:Flutter Issue 29515):

    extension StateExtension<T extends StatefulWidget> on State<T> {
      Stream waitForStateLoading() async* {
        while (!mounted) {
          yield false;
        }
        yield true;
      }
    
      Future<void> postInit(VoidCallback action) async {
        await for (var isLoaded in waitForStateLoading()) {}
        action();
      }
    }
    

    注意:您也可以使用after_init 包来实现相同目的,而不是编写 postInit 代码。

    其他几篇讨论类似问题的帖子:

    【讨论】:

    • 感谢您的及时回复。但是对于拿笔记这样简单的事情来说,这不是太多了。我可以使用未来的构建器轻松获取它,但是使用提供者获取它是反模式吗?
    • @AseemShrey: 1) 你可以从它的父类传递列表(你已经在那里监听变化) 2) 我不能确切地说使用未来的构建器是否是一种反模式,我没有看到有人这么说,我相信我们可以适当地混合和匹配不同的状态管理技术
    • @AseemShrey 还要检查更新答案中包含的链接中的帖子
    • 是的,我确实看过它。所谓反模式,我的意思是使用提供者来获取数据,是一种反模式
    • @AseemShrey 是的,我认为实施存在问题。如果您有兴趣检查待办事项列表的类似实现,它以一种很好的方式完成:dev.to/shakib609/…
    猜你喜欢
    • 2016-05-28
    • 1970-01-01
    • 2021-09-18
    • 1970-01-01
    • 1970-01-01
    • 2020-07-03
    • 2020-02-21
    • 2016-05-17
    • 1970-01-01
    相关资源
    最近更新 更多