Skip to content

FocusNode disposed twice when using ReactivePhoneFormField with reactive_forms 18.x #206

@JulienDeshayes

Description

@JulienDeshayes

Hi 👋

After updating to the latest versions:

  • Flutter: 3.32.x
  • reactive_forms: 18.1.1
  • reactive_phone_form_field: 5.0.2
  • phone_form_field: 10.0.10

I’m getting a FocusNode was used after being disposed error whenever I navigate away from a page that contains a ReactivePhoneFormField.

Stack trace

A FocusNode was used after being disposed.
#0      ChangeNotifier.debugAssertNotDisposed.<anonymous closure> (package:flutter/src/foundation/change_notifier.dart:182:9)
#1      ChangeNotifier.debugAssertNotDisposed (package:flutter/src/foundation/change_notifier.dart:189:6)
#2      ChangeNotifier.dispose (package:flutter/src/foundation/change_notifier.dart:377:27)
#3      FocusNode.dispose (package:flutter/src/widgets/focus_manager.dart:1119:11)
#4      FocusController.dispose (package:reactive_forms/src/models/focus_controller.dart:69:17)
#5      ReactiveFocusableFormFieldState._unregisterFocusController (package:reactive_forms/src/widgets/reactive_focusable_form_field.dart:66:22)
#6      ReactiveFormFieldState.dispose (package:reactive_forms/src/widgets/reactive_form_field.dart:181:5)
#7      _ReactivePhoneFormFieldState.dispose (package:reactive_phone_form_field/src/reactive_phone_form_field.dart:263:11)

Notes

Two days ago i had a similar issue with TextEditorController from phone_form_field. It was resolved in their latest version 10.0.10.
Here is a preview of the resolved stacktrace :

A TextEditingController was used after being disposed.
Once you have called dispose() on a TextEditingController, it can no longer be used.
#0      ChangeNotifier.debugAssertNotDisposed.<anonymous closure> (package:flutter/src/foundation/change_notifier.dart:182:9)
#1      ChangeNotifier.debugAssertNotDisposed (package:flutter/src/foundation/change_notifier.dart:189:6)
#2      ChangeNotifier.dispose (package:flutter/src/foundation/change_notifier.dart:377:27)
#3      PhoneController.dispose (package:phone_form_field/src/phone_controller.dart:121:40)
#4      _ReactivePhoneFormFieldState.dispose (package:reactive_phone_form_field/src/reactive_phone_form_field.dart:261:23)

I think a similar behavior is happening with FocusNode.

Steps to reproduce

Here is a minimal example to test.
Reproduction steps :

  1. Run the app
  2. Go to the profile page
  3. Click on the phone field
  4. Return to the home page (via the back button)
  5. Find the error stacktrace in your logs
import 'package:flutter/material.dart';
import 'package:reactive_forms/reactive_forms.dart';
import 'package:reactive_phone_form_field/reactive_phone_form_field.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(title: 'FocusNode Dispose Bug Demo', home: const HomePage());
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Home")),
      body: Center(
        child: ElevatedButton(
          child: const Text("Go to profile page"),
          onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (_) => const ProfilePage()));
          },
        ),
      ),
    );
  }
}

class ProfilePage extends StatelessWidget {
  const ProfilePage({super.key});

  FormGroup _buildForm() => fb.group({'phone': FormControl<PhoneNumber>()});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Profile")),
      body: ReactiveForm(
        formGroup: _buildForm(),
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            children: [
              ReactivePhoneFormField(
                formControlName: 'phone',
                validationMessages: {ValidationMessage.required: (_) => 'Phone required'},
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                child: const Text("Back"),
                onPressed: () {
                  Navigator.of(context).pop();
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Thank you for your help !

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions