Skip to content

DidChangeDependencies may be unsafe #34130

Closed

Description

@rrousselGit

According to the documentation, didChangeDependencies can be overridden to perform expensive work that shouldn't be done on every build call.

But the way the life-cycle works right now, didChangeDependencies doesn't guarantee that build will be called.

This causes important issues, because the life-cycle may start some expensive work that will never be needed.

As an example, consider the widget Foo that depends on the InheritedWidget MyInherited through didChangeDependencies to perform some expensive work.

Then consider the following widget tree:

MyInherited(
  value: 0,
  child: Foo(),
)

That is later rebuilt to:

MyInherited(
  // updateShouldNotify will return true
  value: 42,
  // Foo is removed from the tree
  child: Container(),
)

then in that situation, Foo.didChangeDependencies will get called even although Foo gets removed from the widget tree and disposed.

Activity

  1. rrousselGit commented on Jun 9, 2019

    @rrousselGit
    ContributorAuthor

    For State.didChangeDependencies, the fix is relatively simple:

    class StatefulElement extends ComponentElement {
      bool _didChangeDependencies = true;
    
      @override
      void didChangeDependencies() {
        _didChangeDependencies = true;
        super.didChangeDependencies();
      }
    
      @override
      Widget build() {
        if (_didChangeDependencies) {
          _didChangeDependencies = false;
          state.didChangeDependencies();
        }
        return super.build();
      }
    }

    It is probably reasonable to not change the behavior of Element didChangeDependencies and only update State.didChangeDependencies.

  2. added
    frameworkflutter/packages/flutter repository. See also f: labels.
    c: performanceRelates to speed or footprint issues (see "perf:" labels)
    on Jun 10, 2019
  3. eseidelGoogle commented on Jun 17, 2019

    @eseidelGoogle
    Contributor

    @Hixie or @goderbauer may know why this method exists.

  4. added this to the milestone on Jan 10, 2020
  5. dnfield commented on Jan 27, 2020

    @dnfield
    Contributor

    Full test case:

    import 'package:flutter/material.dart';
    import 'package:flutter_test/flutter_test.dart';
    
    void main() {
      testWidgets('Counter increments smoke test', (WidgetTester tester) async {
        GlobalKey key = GlobalKey();
        print('First');
        await tester.pumpWidget(MyInherited(key, 10, MyStatefulWidget()));
        print('Second');
        await tester.pumpWidget(MyInherited(key, 20, Container(color: Colors.blue)));
        print('Done');
      });
    }
    
    class MyInherited extends InheritedWidget {
      const MyInherited(Key key, this.value, Widget child) : super(key: key, child: child);
    
      final int value;
      @override
      bool updateShouldNotify(MyInherited oldWidget) => oldWidget.value != value;
    }
    
    class MyStatefulWidget extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => MyState();
    }
    
    class MyState extends State<MyStatefulWidget> {
      int didChangeDependenciesCount = 0;
      @override
      void didChangeDependencies() {
        super.didChangeDependencies();
        didChangeDependenciesCount++;
        assert(didChangeDependenciesCount == 1);
        print('didChangeDependencies');
      }
    
      @override
      Widget build(BuildContext context) {
        print('build');
        context.dependOnInheritedWidgetOfExactType<MyInherited>();
        return Container(color: Colors.red);
      }
    }
  6. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    and removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Jan 27, 2020
  7. dnfield commented on Jan 27, 2020

    @dnfield
  8. self-assigned this
    on Jan 27, 2020
  9. modified the milestones: , January 2020 on Jan 27, 2020
  10. github-actions commented on Aug 23, 2021

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  11. locked as resolved and limited conversation to collaborators on Aug 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

c: performanceRelates to speed or footprint issues (see "perf:" labels)frameworkflutter/packages/flutter repository. See also f: labels.

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions