flutter didChangeDependencies和initState有什么区别?

mznpcxlj  于 2023-04-13  发布在  Flutter
关注(0)|答案(9)|浏览(187)

我是flutter的新手,当我想在InitState中调用我的上下文时,它会抛出一个错误:它是关于BuildContext.inheritFromWidgetOfExactType的,但是我使用了didChangeDependencies,它可以正常工作。
现在我有两个问题:
1-为什么在initState中调用我们的上下文不起作用,但在从didChangeDependencies中调用时却起作用?(因为我在官方文档This method is also called immediately after [initState]中读到,这两个都将在构建方法之前被调用。
2-为什么我们可以访问构建方法之外的上下文(因为在那里我们有build(BuildContext context),我们可以使用我们的上下文,但在didChangeDependencies中,我们没有像didChangeDependencies(BuildContext context)这样的东西,所以我们可以从哪里调用上下文来使用它)?

tyky79it

tyky79it1#

从State加载其依赖项的那一刻起,我们就可以使用State的上下文。
在调用build时,context是可用的,并作为参数传递。
现在继续,initstate在状态加载其依赖项之前被调用,因此没有可用的上下文,如果在 initstate 中使用上下文,则会得到一个错误。然而,didChangeDependencies在状态加载其依赖项后不久被调用,此时上下文可用,因此您可以在这里使用上下文。
然而,它们都是在调用build之前调用的。唯一的区别是,一个是在状态加载其依赖项之前调用的,另一个是在状态加载其依赖项之后不久调用的。

2uluyalo

2uluyalo2#

我发现initStatedidChangeDependencies之间有一个显著的区别:

  • initState对于一个widget只调用一次
  • didChangeDependencies可能在每个小部件生命周期中被调用多次(在我的例子中,它是在键盘出现/消失时被调用的)
csga3l58

csga3l583#

initState()当新的Widget插入到树中时调用。框架将为它创建的每个[State]对象调用此方法一次。这将被调用一次,因此执行只需要执行一次的工作,但记住context不能在这里使用,因为widget状态被加载,只有initState()工作被完成。

语法:

@override
  void initState() {
    debugPrint('initState()');
    super.initState();
  }

didChangeDependencies()当这个[State]对象的依赖关系改变时调用。
那么,确切地说,**它是如何被调用的?**根据上面的定义,它看起来像是在状态改变后被调用的,但是我们如何知道状态被改变了呢?

示例:

下面的示例使用Provider状态管理机制来更新父控件的子控件。Provider有一个名为updateShouldNotify的属性,该属性决定状态是否更改。如果它返回true,则只有didChangeDependenciesChildWidget类中被调用。
updateShouldNotify在内部默认返回true,因为它知道状态发生了变化。**那么为什么我们需要updateShouldNotify?**它的需要是因为如果有人想要在特定条件下更新状态,例如:如果UI只需要显示even值,那么我们可以添加一个条件,如

updateShouldNotify: (oldValue, newValue) => newValue % 2 == 0,

代码段:

class ParentWidget extends StatefulWidget {
  ParentWidget({Key key, this.title}) : super(key: key);

  final String title;

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

class _ParentWidgetState extends State<ParentWidget> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Life Cycle'),
      ),
      body: Provider.value(
        value: _counter,
        updateShouldNotify: (oldValue, newValue) => true,
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'Press Fab button to increase counter:',
              ),
              ChildWidget()
            ],
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

class ChildWidget extends StatefulWidget {
  @override
  _ChildWidgetState createState() => _ChildWidgetState();
}

class _ChildWidgetState extends State<ChildWidget> {
  int _counter = 0;

  @override
  void initState() {
    print('initState(), counter = $_counter');
    super.initState();
  }

  @override
  void didChangeDependencies() {
    _counter = Provider.of<int>(context);
    print('didChangeDependencies(), counter = $_counter');
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    print('build(), counter = $_counter');
    return Text(
      '$_counter',
    );
  }
}

输出日志:

I/flutter ( 3779): didChangeDependencies(), counter = 1
I/flutter ( 3779): build(), counter = 1

详细说明:

https://medium.com/@jitsm555/differentiate-between-didchangedependencies-and-initstate-f98a8ae43164?sk=47b8dda310f307865d8d3873966a9f4f

fhg3lkii

fhg3lkii4#

  1. According to initState documentation
    不能从此方法中使用BuildContext.inheritFromWidgetOfExactType。但是,将在此方法之后立即调用didChangeDependencies,并且可以在此方法中使用BuildContext.inheritFromWidgetOfExactType
    所以你需要在didChangeDependencies中使用BuildContext.inheritFromWidgetOfExactType
    1.每个Widget都有自己的context。这就是为什么你可以访问构建方法之外的上下文。
    关于build(BuildContext context)build方法从父控件接受context。这意味着这个参数BuildContext context不是当前控件的上下文,而是其父控件的上下文。
w46czmvw

w46czmvw5#

contextbuild()之外神秘地可访问的概念是困扰我的一个。我认为澄清这个微妙的点补充了对第一个问题的其他答案中给出的解释。

如何从build()方法外部访问context

混乱源于(错误)假设context需要传递给State.build()。请注意,State类已经有一个context属性,根据文档,它在这里被“冗余地提供”给build(),以便它的签名与WidgetBuilder的签名匹配。但是,这不是与StatelessWidget相同的build()方法。

v64noz0r

v64noz0r6#

initState()是小部件创建后调用的第一个方法,类似于Android中的onCreate()或iOS中的viewDidLoad()
框架第一次构建小部件时,它会在initState()之后调用didChangeDependencies(),如果状态对象依赖于一个已更改的继承小部件,它可能会再次调用didChangeDependencies()

来源:Flutter Apprentice由Kodeco出版

9vw9lbht

9vw9lbht7#

当此State对象的依赖项更改时调用。
例如,如果先前对build的调用引用了一个后来更改的InheritedWidget,则框架将调用此方法来通知此对象有关更改。
该方法也是在initState之后立即调用的,从该方法调用BuildContext.dependOnInheritedWidgetOfExactType是安全的。
事实上,子类很少覆盖这个方法,因为框架总是在依赖关系改变后调用build。一些子类确实覆盖这个方法,因为当它们的依赖关系改变时,它们需要做一些昂贵的工作(例如,网络获取),并且这些工作对于每个构建来说都太昂贵了。

6qqygrtg

6qqygrtg8#

  • 这是一个补充回答,显示了OP所描述的内容。*

StatefulWidgetState类具有context属性。此生成上下文首先在didChangeDependencies中可用。尝试在initState中使用context将导致错误。

class HomeWidget extends StatefulWidget {
  const HomeWidget({Key key}) : super(key: key);

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

class _HomeWidgetState extends State<HomeWidget> {
  @override
  void initState() {
    print('initState');
    // print(Theme.of(context));        // ERROR!
    super.initState();
  }

  @override
  void didChangeDependencies() {
    print('didChangeDependencies');
    print(Theme.of(context));           // OK
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    print('build');
    print(Theme.of(context));           // OK
    return Container();
  }
}

按以下顺序运行print语句:

initState
didChangeDependencies
ThemeData#93b06
build
ThemeData#93b06

参见Working with didChangeDependencies() in Flutter

x6492ojm

x6492ojm9#

你仍然可以在initState()方法中使用context,它的hack但是工作,所有你需要做的就是寻找延迟,无论你需要执行什么,都有上下文,就像这样:

@override
  void initState() {
    Future.delayed(Duration.zero).then((_) {
      // you code with context here
    });
    super.initState();
  }

相关问题