0

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?

ximmyxiao
  • 2,622
  • 3
  • 20
  • 35

1 Answers1

1

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<InheritedParent> createState() => _InheritedParentState();
}

class _InheritedParentState extends State<InheritedParent> {
  @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 'const InheritedChild()'?
              onPressed: () => 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<Inherited>();
  }

  @override
  bool updateShouldNotify(Inherited oldWidget) {
    /// Change this to see the behavior.
    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,
      /// Access the color specified in 'Inherited'.
      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<InheritedChild> {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 128.0,
      height: 128.0,
      /// This widget DEPENDS on the [Inherited] to rebuild.
      color: context.dependOnInheritedWidgetOfExactType<Inherited>()?.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;
}
offworldwelcome
  • 1,314
  • 5
  • 11
  • Thanks @offworldwelcome , so updateShouldNotify only work with const widget rebuilding? maybe remove the const directive can do the same work? – ximmyxiao Jul 18 '23 at 00:50
  • or the main purpose of updateShouldNotify is to remove the unnecessarily rebuild of inheriwidget'children ? ( and must work with const directive for the child) – ximmyxiao Jul 18 '23 at 01:26
  • @ximmyxiao InheritedWidgets allow you to share data in a tree (any child widget can call `Inherited.of(context)` to access data. Another benefit is that this allows you to instantiate `const` widgets that will only rebuild when the data they depend on changes; for example, the `provider` package uses `InheritedWidget` under the hood. To answer your question: this is an optimization that allows you to minimize rebuilds as well as target specific sections of your widget tree for rebuild, instead of having to rebuild the entire tree. – offworldwelcome Jul 18 '23 at 13:11