Skip to content

Conversation

@ksokolovskyi
Copy link
Contributor

@ksokolovskyi ksokolovskyi commented Feb 16, 2025

Fixes #161698

Description

  • Updates Container widget to be Stateful and use GlobalKey to preserve the child's state
  • Replaces some occurrences of Container in framework_test.dart with custom _Wrapper widget to retain tests readability. Without this change, we would have to check for KeyedSubtree-[GlobalKey#00000] in tests, instead of Container-[<1>] which decreases readability.
  • Replace Container with SizedBox in lookup_boundary_test.dart, because the test didn't expect the additional KeyedSubtree widget inside the Container.
  • Replaces Container with KeyedSubtree in packages/flutter_test/lib/src/binding.dart. This is because using the Container in TestWidgetsFlutterBinding._runTestBody introduces two additional GlobalKey which affect existing GlobalKey tests.

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
  • I signed the [CLA].
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is [test-exempt].
  • I followed the [breaking change policy] and added [Data Driven Fixes] where supported.
  • All existing and new tests are passing.

@github-actions github-actions bot added a: tests "flutter test", flutter_test, or one of our tests framework flutter/packages/flutter repository. See also f: labels. labels Feb 16, 2025
@ksokolovskyi
Copy link
Contributor Author

There is one failing test in flutter/packages/rfw package: https://github.com/flutter/packages/blob/8542af3ddbe4a3fd353b31b28f5fb04065097b3b/packages/rfw/test/runtime_test.dart#L894C15-L894C41

This test tries to get the element of the Container widget pumped by the TestWidgetsFlutterBinding._runTestBody function. This PR replaces that Container with KeyedSubtree (https://github.com/flutter/flutter/pull/163419/files#diff-d34dbaacc51359fa05706c29bf6f9defc134c57d31b2d84313b1bbcc54bd2773L1052) which breaks the test.

Could you please advise what to do in this case?

@justinmc
Copy link
Contributor

@LongCatIsLooong FYI I think we were discussing this problem before you went on leave, see #161698.

@flutter-dashboard
Copy link

This pull request executed golden file tests, but it has not been updated in a while (20+ days). Test results from Gold expire after as many days, so this pull request will need to be updated with a fresh commit in order to get results from Gold.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@Piinks
Copy link
Contributor

Piinks commented Mar 11, 2025

Hey from triage, @LongCatIsLooong and @ksokolovskyi , what is the status of this PR?

@ksokolovskyi ksokolovskyi force-pushed the fix-container-child-state-loss branch from 99b8473 to 9fc1456 Compare March 12, 2025 06:52
@ksokolovskyi
Copy link
Contributor Author

Hi @Piinks. From my side, the PR is ready for review, but I am unsure how to proceed with one failing test in the flutter/packages/rfw package. I described the issue in a comment above.

Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this PR will require a lot of work to prove this is a valid solution that is not negatively affecting performance, but I appreciate you taking on such a difficult and fundamental problem @ksokolovskyi!

This is the failing rfw test. Can you see if it's something trivial that can be updated? It's probably just depending on Container producing a ColoredBox even when not given a color. https://github.com/flutter/packages/blob/ff7724c18a803542fc709f942c3bf1cecf7e4864/packages/rfw/test/runtime_test.dart#L894

/// * Cookbook: [Animate the properties of a container](https://docs.flutter.dev/cookbook/animation/animated-container)
/// * The [catalog of layout widgets](https://docs.flutter.dev/ui/widgets/layout).
class Container extends StatelessWidget {
class Container extends StatefulWidget {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder what the performance implications are about changing this to a stateful widget since Container is used all over the place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@justinmc what could you suggest to prove that there is no performance decrease?
Maybe some benchmark like #148261?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am also against turning this into stateful widget.

I am not sure what may be a good way to write a benchmark for state vs statefulwidget comparison. We can't accurately estimate how many containers are used in real world.

}

class _ContainerState extends State<Container> {
final GlobalKey _childGlobalKey = GlobalKey();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also might be a performance concern. Somewhat related: #161698 (comment)


if (child == null && (constraints == null || !constraints!.isTight)) {
if (current != null) {
current = KeyedSubtree(key: _childGlobalKey, child: current);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chunhtai I think you and I talked about solving this problem with a KeyedSubtree before and decided against it, do you remember the details at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@justinmc @chunhtai could you share your concerns about using KeyedSubtree?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the main concern is the use of global key. They are a lot more costly than using regular key.

@ksokolovskyi
Copy link
Contributor Author

Hi @justinmc, thanks a lot for taking a look at this PR!
I opened PR with test fixes for the rfw package and am waiting for its approval: flutter/packages#9063

Copy link
Contributor

@chunhtai chunhtai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid using globalkey and statefulwidget as well in a basic building block widget.

/// * Cookbook: [Animate the properties of a container](https://docs.flutter.dev/cookbook/animation/animated-container)
/// * The [catalog of layout widgets](https://docs.flutter.dev/ui/widgets/layout).
class Container extends StatelessWidget {
class Container extends StatefulWidget {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am also against turning this into stateful widget.

I am not sure what may be a good way to write a benchmark for state vs statefulwidget comparison. We can't accurately estimate how many containers are used in real world.


if (child == null && (constraints == null || !constraints!.isTight)) {
if (current != null) {
current = KeyedSubtree(key: _childGlobalKey, child: current);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the main concern is the use of global key. They are a lot more costly than using regular key.

auto-submit bot pushed a commit to flutter/packages that referenced this pull request Jun 17, 2025
…estWidgets`. (#9063)

This PR updates `rfw` package tests to no longer depend on a `Container` pumped via `testWidgets` to unblock further work on flutter/flutter#163419

## Pre-Review Checklist

[^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
@ksokolovskyi
Copy link
Contributor Author

Closing this PR as the solution proposed is not an acceptable one for a basic building block widget.
The possible solutions are outlined here: #161698 (comment)

Ortes pushed a commit to Ortes/packages that referenced this pull request Jun 25, 2025
…estWidgets`. (flutter#9063)

This PR updates `rfw` package tests to no longer depend on a `Container` pumped via `testWidgets` to unblock further work on flutter/flutter#163419

## Pre-Review Checklist

[^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
vashworth pushed a commit to vashworth/packages that referenced this pull request Jul 30, 2025
…estWidgets`. (flutter#9063)

This PR updates `rfw` package tests to no longer depend on a `Container` pumped via `testWidgets` to unblock further work on flutter/flutter#163419

## Pre-Review Checklist

[^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: tests "flutter test", flutter_test, or one of our tests framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Container can lose its child's state

4 participants