InheritedWidget的updateShouldNotify需要存在吗?

huangapple go评论69阅读模式
英文:

Does the InheritedWidget's updateShouldNotify need to exist?

问题

updateShouldNotify的官方注释表示它可以控制当重建InheritedWidget时是否重建其子构建。

/// 框架是否应通知从此小部件继承的小部件。
///
/// 当重建此小部件时,有时我们需要重建继承自此小部件的小部件,但有时我们不需要。例如,如果此小部件持有的数据与`oldWidget`持有的数据相同,那么我们就不需要重建继承了`oldWidget`持有数据的小部件。
///
/// 框架通过将具有与此对象相同的[runtimeType]的给定小部件作为参数调用此函数来区分这些情况,该小部件保证具有相同的[runtimeType]。
  
@protected
bool updateShouldNotify(covariant InheritedWidget oldWidget);

但是,**如果重新构建InheritedWidget,那么所有继承自此小部件的小部件都将被重新构建**,无论updateShouldNotify返回false还是true。**因为这些小部件是InheritedWidget的子级**。

有人能给一个示例吗?即当重新构建InheritedWidget时,子级不会随updateShouldNotify而重建?
英文:

The official comment of updateShouldNotify says it can control the InheritedWidget's child build or not when the InheritedWidget is rebuild.

  /// Whether the framework should notify widgets that inherit from this widget.
  ///
  /// When this widget is rebuilt, sometimes we need to rebuild the widgets that
  /// inherit from this widget but sometimes we do not. For example, if the data
  /// held by this widget is the same as the data held by `oldWidget`, then we
  /// do not need to rebuild the widgets that inherited the data held by
  /// `oldWidget`.
  ///
  /// The framework distinguishes these cases by calling this function with the
  /// widget that previously occupied this location in the tree as an argument.
  /// The given widget is guaranteed to have the same [runtimeType] as this
  /// object.


@protected
  bool updateShouldNotify(covariant InheritedWidget oldWidget);

But if the InheritedWidget is rebuilt , then all the widgets inherited from the this widget will rebuilt no matter this updateShouldNotify is return false or true. because these widgets are the children of the InheritedWidget .

Can anybody give an example of children do not rebuild with updateShouldNotify when the InheritedWidget is rebuilt?

答案1

得分: 1

以下是翻译好的部分:

我可以给你一个简单的示例:如果从不通知它,InheritedWidgetconst 子组件如何被重建?

运行以下示例代码以查看行为。将 updateShouldNotify 的返回值从 false 更改为 true,然后点击按钮。

/// 这是将重建 [InheritedWidget] 的 [StatefulWidget]。
class InheritedParent extends StatefulWidget {
  const InheritedParent({super.key});

  @override
  State<InheritedParent> createState() => _InheritedParentState();
}

class _InheritedParentState extends State<InheritedParent> {
  @override
  Widget build(BuildContext context) {
    return Inherited(
      /// 将随机颜色传递给 [InheritedWidget]。
      color: _getRandomColor(),
      child: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            /// 继承的子组件是常量的。
            const InheritedChild(),
            FloatingActionButton(
              /// 我们调用 setState,因此整个子树应该被重建...
              /// 但是对于 'const InheritedChild()' 呢?
              onPressed: () => setState(() {}),
              child: const Icon(Icons.add),
            ),
          ],
        ),
      ),
    );
  }

  /// 此方法将返回随机颜色。
  Color _getRandomColor() {
    return Colors.primaries[math.Random().nextInt(Colors.primaries.length)];
  }
}

/// 提供 [Color] 给其子组件通过上下文。
class Inherited extends InheritedWidget {
  const Inherited({
    super.key,
    required this.color,
    required super.child,
  });

  final Color color;

  static Inherited? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<Inherited>();
  }

  @override
  bool updateShouldNotify(Inherited oldWidget) {
    /// 更改此处以查看行为。
    return false;
  }
}

class InheritedChild extends StatefulWidget {
  const InheritedChild({super.key});

  @override
  State<InheritedChild> createState() => _InheritedChildState();
}

class _InheritedChildState extends State<InheritedChild> {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 128.0,
      height: 128.0,
      /// 访问在 'Inherited' 中指定的颜色。
      color: Inherited.of(context)?.color,
    );
  }
}

InheritedWidget 允许您过滤重建(调用 setState),以便只有在它们依赖的任何数据(来自父 InheritedWidget)发生更改时才会重建后代。

尽管通常的习惯用法是为继承的小部件提供一个静态的 of(context) 方法,但请记住,它们也可以在没有该方法的情况下使用;为了明确起见:

class _InheritedChildState extends State<InheritedChild> {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 128.0,
      height: 128.0,
      /// 这个小部件依赖于 [Inherited] 来重建。
      color: context.dependOnInheritedWidgetOfExactType<Inherited>()?.color,
    );
  }
}

从文档中可以了解到:“返回给定类型 T 的最近的小部件,并在其上创建一个依赖项”。

当创建依赖关系时,子小部件会被注册以获取更改通知。它何时会收到更改通知呢?

updateShouldNotify 返回 true 时。

因此,Inherited.updateShouldNotify 的正确实现是:

@override
bool updateShouldNotify(Inherited oldWidget) {
  /// 子小部件为了正确构建自身所依赖的数据。
  return oldWidget.color != color;
}
英文:

I can give you a simple example: how can a const child widget of the InheritedWidget ever be rebuilt if it is never notified?

Run this sample code to see the behavior. Change the return value of updateShouldNotify from false to true and then tap on the button.

/// This is the [StatefulWidget] that will rebuild the [InheritedWidget].
class InheritedParent extends StatefulWidget {
const InheritedParent({super.key});
@override
State&lt;InheritedParent&gt; createState() =&gt; _InheritedParentState();
}
class _InheritedParentState extends State&lt;InheritedParent&gt; {
@override
Widget build(BuildContext context) {
return Inherited(
/// Pass the random color to the [InheritedWidget].
color: _getRandomColor(),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
/// The inherited child is constant.
const InheritedChild(),
FloatingActionButton(
/// We call setState, so the entire subtree should be rebuilt...
/// but what about &#39;const InheritedChild()&#39;?
onPressed: () =&gt; setState(() {}),
child: const Icon(Icons.add),
),
],
),
),
);
}
/// This method will return a random color.
Color _getRandomColor() {
return Colors.primaries[math.Random().nextInt(Colors.primaries.length)];
}
}
/// The widget that provides a [Color] to its descendants through the context.
class Inherited extends InheritedWidget {
const Inherited({
super.key,
required this.color,
required super.child,
});
final Color color;
static Inherited? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType&lt;Inherited&gt;();
}
@override
bool updateShouldNotify(Inherited oldWidget) {
/// Change this to see the behavior.
return false;
}
}
class InheritedChild extends StatefulWidget {
const InheritedChild({super.key});
@override
State&lt;InheritedChild&gt; createState() =&gt; _InheritedChildState();
}
class _InheritedChildState extends State&lt;InheritedChild&gt; {
@override
Widget build(BuildContext context) {
return Container(
width: 128.0,
height: 128.0,
/// Access the color specified in &#39;Inherited&#39;.
color: Inherited.of(context)?.color,
);
}
}

The InheritedWidget allows you to filter rebuilds (calls to setState so that descendants are only rebuilt when any data that they depend on (from the parent InheritedWidget) changes.

While the convenience idiom is to provide a static of(context) method for your inherited widgets, remember that they can be used without one; to make it explicit:

class _InheritedChildState extends State&lt;InheritedChild&gt; {
@override
Widget build(BuildContext context) {
return Container(
width: 128.0,
height: 128.0,
/// This widget DEPENDS on the [Inherited] to rebuild.
color: context.dependOnInheritedWidgetOfExactType&lt;Inherited&gt;()?.color,
);
}
}

From the documentation: "Returns the nearest widget of the given type T and creates a dependency on it".

When a dependency is created, the child widget is registered for changes. When does it get notified of the changes?

When updateShouldNotify return true.

Therefore, the correct implementation of Inherited.updateShouldNotify is:

@override
bool updateShouldNotify(Inherited oldWidget) {
/// The data that the child widget depends on in order to properly
/// build itself.
return oldWidget.color != color;
}

huangapple
  • 本文由 发表于 2023年7月17日 17:25:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76703080.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定