在 Widget 的 initState 或初始化生命周期中使用 Provider

Using Provider in Widget's initState or initialising life-cycle

所以在学习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 中,是否没有其他方法 运行ning 初始化代码?或者有没有计划引入一些更可行的东西?

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

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

我在didChangeDependencies里面实现如下

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

可以将代码安排到 运行 当前帧的末尾。如果安排在 initState() 内,似乎在代码为 运行ning 时 Widget 已完全设置。

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

@override
  void initState() {
    super.initState();

    SchedulerBinding.instance.addPostFrameCallback((_) {
      // Some provider code that gets/sets some state 
    })
  }

您也可以为此使用 WidgetsBinding.instance.addPostFrameCallback()。在 Widget built/loaded 之后,出于 运行ning 代码的目的,它们的行为相同,但是 here 是关于差异的更多细节。

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

import 'package:flutter/scheduler.dart';

您可以将 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();
    
}