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

Assertion Error with useExpansionTileController #414

Closed
kovaccc opened this issue Feb 4, 2024 · 5 comments
Closed

Assertion Error with useExpansionTileController #414

kovaccc opened this issue Feb 4, 2024 · 5 comments
Assignees
Labels
bug Something isn't working question Further information is requested

Comments

@kovaccc
Copy link

kovaccc commented Feb 4, 2024

An assertion error is occurring in the CustomExpansionTile widget when using the useExpansionTileController hook from the flutter_hooks package. The issue seems to manifest when accessing the isExpanded property of ExpansionTileController. The assertion error suggests that the controller's state is null at the time of access.

Steps to reproduce the behavior:

  1. Create a CustomExpansionTile widget as a HookWidget.
  2. Use useExpansionTileController to get an instance of ExpansionTileController.
  3. Try to access expansionTileController.isExpanded within the widget's build method.
  4. See error on runtime.
class CustomExpansionTile extends HookWidget {
  // ... [other properties]

  @override
  Widget build(BuildContext context) {
    final expansionTileController = useExpansionTileController();
    return Column(
      // ... [other widget code]
      child: ExpansionTile(
        controller: expansionTileController,
        // ... [other properties]
        trailing: expansionTileController.isExpanded
            ? Assets.icons.minus.svg()
            : Assets.icons.plus.svg(),
        // ... [other properties]
      ),
    );
  }
}

Error message:

======== Exception caught by widgets library =======================================================
The following assertion was thrown building CustomExpansionTile:
'package:flutter/src/material/expansion_tile.dart': Failed assertion: line 49 pos 12: '_state != null': is not true.

The expected behavior is that the CustomExpansionTile should correctly show the expanded or collapsed state based on the isExpanded property of the ExpansionTileController without causing any runtime errors or assertions. The useExpansionTileController hook should properly initialize and manage the state of the ExpansionTileController.

@kovaccc kovaccc added bug Something isn't working needs triage labels Feb 4, 2024
@rrousselGit
Copy link
Owner

The issue is most definitely unrelated to hooks. The controller was correctly created, and the error isn't thrown by flutter_hooks but Flutter.
My guess is that you're trying to use the controller before it is associated with a widget, and therefore trigger this assert.

Also note that your controller isn't listened. So your UI won't update when the value changes.

Two things:

  • Consider raising an issue on the Flutter repo to have them improve their error message
  • Try wrapping your leading in a builder, such as HooKBuilder or ValueListenableBuilder.
    This would delay the isExpanded usage to a point where the controller is linked with a widget
    leading: HookBuilder(
      builder: (context) {
        useListenable(expansionTileController);
        return  expansionTileController.isExpanded
              ? Assets.icons.minus.svg()
              : Assets.icons.plus.svg()
      },

@rrousselGit rrousselGit added question Further information is requested and removed needs triage labels Feb 4, 2024
@kovaccc
Copy link
Author

kovaccc commented Feb 4, 2024

Firstly, thank you for the prompt response and your suggestions. I understand your point that the issue might be due to the ExpansionTileController being used before it's associated with a widget and the controller not being listened to.

Following your advice, I attempted to use HookBuilder along with useListenable for the ExpansionTileController. However, I've run into a type inference issue. When I use useListenable with ExpansionTileController, I encounter the following error:

Couldn't infer type parameter 'T'.
Tried to infer 'ExpansionTileController' for 'T' which doesn't work:
  Type parameter 'T' is declared to extend 'Listenable?' producing 'Listenable?'.
  The type 'ExpansionTileController' was inferred from:
  Parameter 'listenable' declared as 'T' but argument is 'ExpansionTileController'.
Consider passing explicit type argument(s) to the generic.

This seems to suggest a type mismatch between ExpansionTileController and Listenable?, which useListenable expects.

Is there a workaround or a different approach you would recommend for ensuring that the ExpansionTileController is correctly used and listened to within the context of flutter_hooks? Any further guidance would be greatly appreciated. Thank you for your time and help.

@rrousselGit
Copy link
Owner

My bad, it's looking like ExpansionTileController isn't a Listenable.

Looks like you have to use ExpansionTileController.of instead;

leading: Builder(
  builder: (context) {
    final controller = ExpansionTileController.of(context);
    return  expansionTileController.isExpanded
          ? Assets.icons.minus.svg()
          : Assets.icons.plus.svg()
  },

@kovaccc
Copy link
Author

kovaccc commented Feb 4, 2024

No worries. I tried do it your way, it does not throw the error but also not changing the icon

class CustomExpansionTile extends HookWidget {
  final String title;
  final List<Widget> children;
  final EdgeInsets? tilePadding;
  final bool showDivider;

  const CustomExpansionTile({
    required this.title,
    required this.children,
    this.tilePadding,
    this.showDivider = true,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    final expansionTileController = useExpansionTileController();
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Theme(
          data: Theme.of(context).copyWith(dividerColor: Colors.transparent),
          child: ExpansionTile(
            controller: expansionTileController,
            tilePadding: tilePadding,
            expandedAlignment: Alignment.topLeft,
            expandedCrossAxisAlignment: CrossAxisAlignment.start,
            trailing: HookBuilder(
              builder: (context) {
                return expansionTileController.isExpanded
                    ? Assets.icons.minus.svg()
                    : Assets.icons.plus.svg();
              },
            ),
            title: Text(
              title,
              style: context.appTextStyles.paragraph2SemiBold,
            ),
            children: children,
          ),
        ),
        if (showDivider) const CustomDivider(),
      ],
    );
  }
}

I will stick to useState instead.

  @override
  Widget build(BuildContext context) {
    final isExpanded = useState(false);
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Theme(
          data: Theme.of(context).copyWith(dividerColor: Colors.transparent),
          child: ExpansionTile(
            tilePadding: tilePadding,
            expandedAlignment: Alignment.topLeft,
            expandedCrossAxisAlignment: CrossAxisAlignment.start,
            trailing: isExpanded.value
                ? Assets.icons.minus.svg()
                : Assets.icons.plus.svg(),
            title: Text(
              title,
              style: context.appTextStyles.paragraph2SemiBold,
            ),
            onExpansionChanged: (bool expanded) => isExpanded.value = expanded,
            children: children,
          ),
        ),
        if (showDivider) const CustomDivider(),
      ],
    );
  }

@rrousselGit
Copy link
Owner

It's ultimately still unrelated to flutter_hooks. So I'd redirect you to Reddit/StackOverflow/Discord for further help requests :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants