Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested widget does not reparent children with global keys #15

Open
aikalant opened this issue Sep 3, 2022 · 0 comments
Open

Nested widget does not reparent children with global keys #15

aikalant opened this issue Sep 3, 2022 · 0 comments

Comments

@aikalant
Copy link

aikalant commented Sep 3, 2022

When the globally key'd children of a Nested widget vary in order or quantity between rebuilds, it looks like they are not reparented as they would if they were built manually without Nested.

Attached a flutter app demonstrating this - tap the red button a few times to induce an error:
nested_bug.zip

import 'dart:math';

import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
import 'package:nested/nested.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return WidgetsApp(
      title: 'Nested Bug',
      color: const Color.fromARGB(255, 0, 0, 0),
      builder: (context, _) => const App(),
    );
  }
}

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

  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  static final List<GlobalKey> keys = List.generate(10, (index) => GlobalKey());
  var numNestedWidgets = 0;
  var useNested = false;

  @override
  Widget build(BuildContext context) {
    final buttons = Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        GestureDetector(
          onTap: () {
            print("\x1B[2J\x1B[0;0H"); //clear console
            setState(() {
              useNested = false;
              numNestedWidgets = Random().nextInt(10);
            });
          },
          child: Container(
            width: 200,
            height: 100,
            alignment: Alignment.center,
            color: const Color.fromARGB(255, 64, 133, 46),
            child: const Text('rebuild manually'),
          ),
        ),
        Text('nested widgets: $numNestedWidgets',
            style: const TextStyle(color: Color.fromARGB(255, 0, 0, 0))),
        GestureDetector(
          onTap: () {
            print("\x1B[2J\x1B[0;0H"); //clear console
            setState(() {
              useNested = true;
              numNestedWidgets = Random().nextInt(10);
            });
          },
          child: Container(
            width: 200,
            height: 100,
            alignment: Alignment.center,
            color: const Color.fromARGB(255, 133, 46, 46),
            child: const Text('rebuild with Nested'),
          ),
        )
      ],
    );
    if (useNested) {
      print('rebuilding with $numNestedWidgets nested widgets (nested)');
      final nestedWidgets = generateNestedWidgets(context);
      return nestedWidgets.isEmpty
          ? buttons
          : Nested(children: nestedWidgets, child: buttons);
    } else {
      print('rebuilding with $numNestedWidgets nested widgets (manual)');
      return generateNestedWidget(keys.sample(numNestedWidgets), buttons);
    }
  }

  Widget generateNestedWidget(Iterable<GlobalKey> keys, Widget lastChild) {
    return keys.isEmpty
        ? lastChild
        : NestedWidget(
            key: keys.first,
            child: generateNestedWidget(keys.skip(1), lastChild),
          );
  }

  List<SingleChildWidget> generateNestedWidgets(BuildContext context) {
    return keys
        .sample(numNestedWidgets)
        .map((key) => NestedWidget(key: key))
        .toList();
  }
}

class NestedWidget extends SingleChildStatefulWidget {
  const NestedWidget({super.key, super.child});

  @override
  SingleChildState<NestedWidget> createState() => _NestedWidgetState();
}

class _NestedWidgetState extends SingleChildState<NestedWidget> {
  @override
  void initState() {
    print('nested widget state regenerated');
    super.initState();
  }

  @override
  Widget buildWithChild(BuildContext context, Widget? child) {
    return child ?? const SizedBox.shrink();
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant