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

问题描述

所以在学习 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();
  }

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

我见过的唯一另一种方法是使用 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() 内安排,那么在代码运行时,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';
,

您可以在单独的函数中使用 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();
    
}