在initState中调用SetState的重要性

39

setState()方法应该在StatefulWidgetinitState()方法内调用吗?

我的理解是,initState()方法会自动应用状态。

下面的代码不起作用。post对象被评估为空。

  @override
  void initState() {
    ItemService.getItemById(widget.postId).then((DocumentSnapshot doc){
        post = ItemService.getPostFromDocument(doc);
    });
  }

但以下的方法可行。

  @override
  void initState() {
    ItemService.getItemById(widget.postId).then((DocumentSnapshot doc){
      setState((){
        post = ItemService.getPostFromDocument(doc);
      });
    });
  }

有些情况下,即使在同一个类中没有使用setState()也能正常工作。

那么我何时应该在initState()方法中使用setState(),何时不用呢?

另外相关的问题:

我何时应该在我的initState()中调用super.initState()?如果我没调用它会有影响吗?


1
我不确定,但也许你的第一个示例无法工作是因为你没有调用 super.initState()。你试过了吗? - Andrii Turkovskyi
还没有尝试过...但是super.initState()有什么影响?我正在尝试理解它的工作原理。我怀疑这一点,因为在同一个类中,即使不调用supers initState,其他状态也能正常工作。 - Purus
https://dev59.com/GlQK5IYBdhLWcg3wL9Fq - anmol.majhail
已经看过了。它解释了什么是initState,但没有回答我的问题。 - Purus
3个回答

57
setState() 方法通知框架 Stateful widget 的内部状态已经改变。调用该方法会触发小部件使用最新的状态值进行重建,因此在 initState() 生命周期方法中不需要调用它,因为当小部件插入窗口小部件树时(即初始化时)它只会被调用一次。
您可以在这里了解更多关于setState()方法的信息: setState method 至于initState()生命周期方法,每当您覆盖此方法时,您必须在您的方法开头或结尾处调用 super.initState();,否则,您的小部件将遇到一些问题,例如小部件未被插入到窗口小部件树中。
您唯一可以在 initState() 内部使用 setState() 的时间是在回调函数中,就像您在第二段代码片段中所做的那样。这是有效的,因为当回调运行时,小部件已经被初始化并插入到窗口小部件树中,并且需要更新内部状态以触发重建。

此外,需要注意的是setState()只有在小部件已安装的情况下才能正常工作。因此,每个小部件都有一个bool this.mounted属性,您可以在不确定小部件在调用setState()时是否仍处于已安装状态时进行检查。当小部件未安装时调用它可能会导致应用程序崩溃。因此,我建议不要在小部件类之外调用setState()


29

在initState中你不需要使用setState。事实上,如果这样做,它将不起作用。

问题在于,在你的示例中,你没有在initState中调用setState

你所做的是在异步事件上调用setState。但由于它是异步的,initState方法已经完成了。


6
谢谢。但是有点让人困惑...我应该把所有异步调用都放在initState方法中的setState方法内部吗?还是根本不使用它?你的回答提供了两种不同的意思。能否请您解释或提供一个简单的示例...回答:您不必在initState方法中使用setState来包装所有异步调用。如果您需要在异步调用完成后更新界面,那么您可以在异步调用的回调函数中使用setState来更新状态。以下是一个简单的示例:class MyWidget extends StatefulWidget { @override _MyWidgetState createState() => _MyWidgetState(); } class _MyWidgetState extends State { String _data = "Loading..."; @override void initState() { super.initState(); fetchData(); } void fetchData() async { // 执行异步调用 final data = await fetchDataFromServer(); // 在回调函数中更新状态 setState(() { _data = data; }); } @override Widget build(BuildContext context) { return Text(_data); } } - Purus

0

如果你想在initstate()中调用异步方法,那么你必须使用setstate()。但是,如果它不是一个异步方法,那么你会遇到麻烦,因为你会尝试在小部件构建之前重建小部件的状态。基本上答案是肯定的:每当你要在initstate()中执行异步函数时,你都应该调用setstate()。我强烈建议你搜索一下小部件的生命周期。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接