didChangeDependencies和initState之间的区别是什么?

时间:2019-10-14 07:24:13

标签: flutter dart

我是新手,要在InitState中调用上下文时会抛出错误: 这是关于 doc.getElementsByTagName("input")(0).value = "My value" 但是然后我使用didChangeDependencies,它可以正常工作。

现在我有2个问题:

1-为什么我们不能在initState中调用上下文,但是didChangeDependencies没有问题? (因为我在官方文档BuildContext.inheritFromWidgetOfExactType中读过, 并且它们都将在build方法之前被调用。 )

2-为什么我们可以在build方法之外访问上下文(因为那里有This method is also called immediately after [initState],我们可以使用我们的上下文,但是在didChangeDependencies中,我们没有类似build(BuildContext context)的东西,所以从哪里开始可以调用上下文来使用它)?

8 个答案:

答案 0 :(得分:1)

  

从状态加载其依赖项之时起,我们就可以使用状态上下文。

在调用build时,上下文可供我们使用,并作为参数传递。

现在继续前进, 在状态加载其依赖项之前会调用initstate,因此,没有上下文可用,并且如果您在initstate中使用上下文,则会收到一个错误消息。 但是,在状态加载其依赖项后不久,就会调用didChangeDependencies,此时可以使用上下文,因此您可以在这里使用上下文。

  

但是在调用build之前都调用了它们。   唯一的区别是,一个在状态加载其依赖项之前被调用,而另一个在状态加载其依赖项之后被调用。

答案 1 :(得分:1)

当此State对象的依赖项更改时调用。

例如,如果先前的build引用引用了后来更改的 InheritedWidget ,则框架将调用此方法以将该更改通知此对象。

initState 之后也立即调用此方法。从此方法调用 BuildContext.dependOnInheritedWidgetOfExactType 是安全的。

实际上,子类很少重写此方法,因为框架总是在依赖项更改后调用build。一些子类确实重写了此方法,因为当它们的依赖项发生变化时,它们需要做一些昂贵的工作(例如,网络获取),并且对于每个构建而言,所做的工作都太昂贵了。

答案 2 :(得分:1)

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

语法:

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

didChangeDependencies()在此[State]对象的依赖项更改时调用。

那么,就像上面的定义一样,它是如何被调用的?,它看起来像在状态改变后将被调用,但是我们如何知道状态被改变了?

示例:

下面的示例使用Provider状态管理机制从父窗口小部件更新子窗口小部件。 Provider具有一个称为updateShouldNotify的属性,该属性决定状态是否被更改。如果返回的是true,则didChangeDependencies类中只会调用ChildWidget

updateShouldNotify在内部默认情况下返回true,因为它知道状态已更改。 然后我们为什么需要updateShouldNotify?,因为有人要在特定条件下更新状态, 例如:如果用户界面只需要显示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

答案 3 :(得分:0)

  1. According to initState documentation
  

您不能通过此方法使用BuildContext.inheritFromWidgetOfExactType。但是,didChangeDependencies将在此方法之后立即调用,并且BuildContext.inheritFromWidgetOfExactType可以在此处使用。

因此,您需要在BuildContext.inheritFromWidgetOfExactType中使用didChangeDependencies

  1. 每个小部件都有自己的context。这就是为什么您可以在build方法之外访问上下文。

关于build(BuildContext context)build方法从父窗口小部件接受context。这表示此参数BuildContext context不是当前小部件的上下文,而是其父级的上下文。

答案 4 :(得分:0)

我发现initStatedidChangeDependencies之间存在显着差异:

  • initState仅对窗口小部件调用一次
  • 在每个小部件生命周期中,
  • didChangeDependencies可能被多次称为多次(在我的情况下,它是在键盘出现/消失时被调用的)

答案 5 :(得分:0)

您仍然可以在initState()方法中使用上下文,它的hacks可以正常工作,您需要做的就是寻求延迟,无论您需要执行的是什么,都需要延迟,就像这样:

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

答案 6 :(得分:0)

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

StateStatefulWidget 类具有 context 属性。此构建上下文首先在 didChangeDependencies 中可用。尝试在 context 中使用 initState 会导致错误。

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();
  }
}

运行,按以下顺序给出打印语句:

initState
didChangeDependencies
ThemeData#93b06
build
ThemeData#93b06

另见Working with didChangeDependencies() in Flutter

答案 7 :(得分:-1)

答案是here

  

不应从小部件构造函数或State.initState方法中调用此方法,因为如果继承的值发生更改,则不会再次调用这些方法。为了确保在继承值更改时小部件能够正确更新自身,请仅从构建方法,布局和绘制回调,或从State.didChangeDependencies中调用(直接或间接)。