在父 setState 之后,子状态对象被替换(initState)而不是更新(didUpdateWidget)

Posted

技术标签:

【中文标题】在父 setState 之后,子状态对象被替换(initState)而不是更新(didUpdateWidget)【英文标题】:Child state object replaced(initState) instead of updated(didUpdateWidget) after parent setState 【发布时间】:2019-11-20 12:36:16 【问题描述】:

我有一个父子有状态小部件。通常,当父级重建时,我希望它重用现有的子状态并调用 didUpdateWidget。

然而,就我而言,它并没有这样做;相反,它创建了一个全新的状态对象并在其上调用 initState,从而丢失了我之前的所有状态信息。

医生说

By default, the framework matches widgets in the current and previous build according 
to their runtimeType and the order in which they appear.

首先,在这种情况下,“顺序”是什么意思?我假设它意味着小部件树中的位置,对吧? 其次,由于我的 Widget 树没有改变,我希望 Flutter 重用旧状态而不是创建新状态。 我不确定如何调试它。如何检查新旧小部件的“顺序”以查看它们是否不同?

我的代码库相当大,所以我会尽量只包含相关部分:

class Parent extends StatefulWidget 
  @override
  _ParentState createState() => _ParentState();


class _ParentState extends State<Parent> 
  String _remaining;

  void updateRemaining(String remaining) 
    setState(() => _remaining = remaining);
  

  Widget build(BuildContext context) 
    //somewhere
    return Child(updateRemaining:updateRemaining);
  


class Child extends StatefulWidget 
  final Function updateRemaining;
  Child(this.updateRemaining);

  @override
  _ChildState createState() => new _ChildState();


class _ChildState extends State<Child> 

//somewhere:
widget.updateRemaining("0");

在最后一次调用之后:widget.updateRemaining("0");颤振处理子状态并创建一个新状态而不是重用旧状态。

我使用 Flutter 检查器查看了小部件树,但看起来 Homepage(=child widget) 没有相对于 MainApp(=parent widget) 移动

在 widget.updateRemaining("0"); 之前打电话

在 widget.updateRemaining("0"); 之后打电话

【问题讨论】:

您可能想阅读以下***.com/a/56926508/8394265。您的 Parent 小部件可能会做类似的事情。 看起来不是这个原因。由于将小部件子项包装到另一个小部件中而导致的状态丢失对我来说是有意义的,因为子项移动到了小部件树中的不同位置。我编辑了我的帖子以显示我的小部件树,你可以看到它保持不变。我的代码中是否有任何隐藏的东西可以强制处置旧状态和新状态的 initState? 【参考方案1】:

好的,这就是我 THINK 发生的事情 - 如果我错了,请纠正我。 答案在我附加的小部件树中。 如您所见,Scaffold 有一个 GlobalKey,它会更改并因此强制重建,因为根据文档:

使用键来控制框架与其他小部件匹配 小部件重建时的小部件。默认情况下,框架匹配 当前和先前构建中的小部件根据其 runtimeType 和它们出现的顺序。 使用按键, 框架要求两个小部件具有相同的键以及 相同的 runtimeType。

由于键不同,所以 Scaffold 状态对象被处置包括其所有子小部件,并创建一个新的。 显然,创建一个新的状态对象会强制重新创建整个子树,无论它是否与旧的相同。

【讨论】:

以上是关于在父 setState 之后,子状态对象被替换(initState)而不是更新(didUpdateWidget)的主要内容,如果未能解决你的问题,请参考以下文章

即使在调用 setState 之后,React.js 子状态也不会重新渲染?

react生命周期函数

React:在 setState 中设置数组对象

组件未在 setState React 上重新渲染

如何在父进程被杀死/完成时保持子进程处于活动状态(在 Windows 中)

Java中setState(true)一般啥意思