【问题标题】:Using Provider in Widget's initState or initialising life-cycle在 Widget 的 initState 中使用 Provider 或初始化生命周期
【发布时间】:2021-07-14 13:37:47
【问题描述】:

所以在学习 Flutter 的过程中,initState() 似乎不是使用 Providers 的地方,因为它还没有访问必须通过的context。我的导师解决这个问题的方法是使用didChangeDependencies() 生命周期钩子和一个标志,这样里面的任何代码都不会运行超过一次:

bool _isInit = true;

@override
  void didChangeDependencies() {
    if (_isInit) {
      // Some provider code that gets/sets some state
    }
    _isInit = false;
    super.didChangeDependencies();
  }

这对我来说是一次糟糕的开发体验。没有其他方法可以在可以访问context 的 Flutter Widget 中运行初始化代码吗?或者有没有计划推出更实用的东西?

我见过的唯一其他方法是使用Future.delayed,感觉有点“hacky”:

@override
  void initState() {
    Future.delayed(Duration.zero).then(() {
      // Some provider code that gets/sets some state 
    });
    super.initState();
  }

【问题讨论】:

    标签: flutter dart lifecycle flutter-provider flutter-widget


    【解决方案1】:

    我在 didChangeDependencies 里面实现了如下

     @override
    void didChangeDependencies() {
        super.didChangeDependencies();
        if (_isInit) {
          setState(() {
            _isLoading = true;
          });
          Provider.of<Products>(context).fetchAndSetProducts().then((_) {
            setState(() {
              _isLoading = false;
            });
          });
        }
        _isInit = false;
      }
           
    

    【讨论】:

    • 据我了解,这样做的问题是您最终可能会重建不依赖 Provider 数据的嵌套子级。因此,在一个只需要一些数据一次(不监听)的小部件中,如果我使用 Consumer 它可能会导致浪费的重新渲染。在您的示例中,每次更改 Provider 数据时都会重新渲染整个应用程序。
    • 我已经编辑了我的答案可能对你有帮助
    • 您对问题的更新与我在问题中提出的在初始化程序中获取数据的机制相同。您包含的添加的业务逻辑甚至看起来像是直接从我一直关注的教程中提取的。我正在寻找使用变量标志 + didChangeDependencies() 的替代方法。
    【解决方案2】:

    可以安排代码在当前帧结束时运行。如果安排在initState() 内,则似乎在代码运行时 Widget 已完全设置。

    为此,您可以使用SchedulerBinding 实例的addPostFrameCallback 方法:

    @override
      void initState() {
        super.initState();
    
        SchedulerBinding.instance.addPostFrameCallback((_) {
          // Some provider code that gets/sets some state 
        })
      }
    

    您也可以为此使用WidgetsBinding.instance.addPostFrameCallback()。它们在构建/加载 Widget 后运行代码一次的行为相同,但here 提供了更多关于差异的详细信息。

    注意:一定要导入SchedulerBinding所需的文件:

    import 'package:flutter/scheduler.dart';
    

    【讨论】:

      【解决方案3】:

      您可以将 Provider 放在一个单独的函数中,并在 initState() 中调用该函数

      bool isInit = true;
      
      Future<void> fetch() async {
          await Provider.of<someProvider>(context, listen: false).fetch();
      }
      
      @override
        void initState() {
          if (isInit) {
            isInit = false;
            fetch();
          }
        isInit = false;
        super.initState();
          
      }
      

      【讨论】:

        猜你喜欢
        • 2019-02-08
        • 1970-01-01
        • 2015-03-22
        • 1970-01-01
        • 2018-06-06
        • 2016-12-25
        • 2020-09-28
        • 2021-12-12
        • 1970-01-01
        相关资源
        最近更新 更多