Search code examples
flutterdartflutter-getxglobal-key

Duplicate GlobalKey detected in widget tree with Getx and using Get.off(screen)


I am running into a globalKey error after I navigate from LoginScreen to SignUp and When i complete signin and try to go back the errors shows up.

The problem is on the loginscreen i think. I think the error is happening because when it is in login page, it creates an instance of Global key. Then when it goes to signup page, Login page's global key instance is already left there. So, after successful response, when it tries to Get.off(()=>Loginpage) , the previous Global key instance is being found, hence causing an error of duplcate Global Key found.

I am using global key with the Getx. Below The Loginpagecontroller code :

class LoginController extends GetxController {
  final TextEditingController signinEmailTextEditingControler =
      TextEditingController();
  final TextEditingController signinPasswordTextEditingControler =
      TextEditingController();

  GlobalKey<FormState> loginFormKey = GlobalKey<FormState>(debugLabel: '_home');

  bool isLoading = false;
  bool showSigninError = false;

  Future<void> signIn() async {
    try {
      isLoading = true;
      showSigninError = false;
      update();
      if (loginFormKey.currentState!.validate()) {
        final NetworkResponse networkResponse =
            await NetworkCaller().postRequest(
          Urls.login,
          body: {
            "email": signinEmailTextEditingControler.text.trim(),
            "password": signinPasswordTextEditingControler.text
          },
        );
        if (networkResponse.isSuccess) {
          // showSnackMessage(context, "Successfull.", Colors.green);
          Get.off(() => const MainBottomNavBar());
          signinClear();
        } else {
          if (networkResponse.statusCode == 401) {
            showSigninError = true;
            update();
            signinPasswordTextEditingControler.clear();
          } else {
            signinClear();
            // showSnackMessage(
            //   context,
            //   "Something went wrong. Try again latter.",
            //   Colors.red,
            // );
          }
        }
      }
    } finally {
      isLoading = false;
      update();
    }
  }

  void signinClear() {
    signinEmailTextEditingControler.clear();
    signinPasswordTextEditingControler.clear();
  }

  @override
  void dispose() {
    signinEmailTextEditingControler.dispose();
    signinPasswordTextEditingControler.dispose();
    super.dispose();
  }
}

Below The signup page controler code:

class SignupController extends GetxController {
  final TextEditingController emailTextEditingControler =
      TextEditingController();
  final TextEditingController passwordTextEditingControler =
      TextEditingController();

  final TextEditingController firstNameTextEditingControler =
      TextEditingController();
  final TextEditingController lastNameTextEditingControler =
      TextEditingController();
  final TextEditingController phoneTextEditingControler =
      TextEditingController();

  GlobalKey<FormState> signupFormKey = GlobalKey<FormState>(debugLabel: '_homeScreenkey');

  bool isLoading = false;

  Future<void> signup(BuildContext context) async {
    try {
      isLoading = true;
      update();
      if (signupFormKey.currentState!.validate()) {
        final NetworkResponse response = await NetworkCaller().postRequest(
          Urls.registration,
          body: {
            "email": emailTextEditingControler.text.trim(),
            "firstName": firstNameTextEditingControler.text.trim(),
            "lastName": lastNameTextEditingControler.text.trim(),
            "mobile": phoneTextEditingControler.text.trim(),
            "password": passwordTextEditingControler.text,
            "photo": ""
          },
        );

        if (response.isSuccess) {
          signupClear();
          Get.offAl(() => LoginScreen());
          update();
          
          // showSnackMessage(
          //   context,
          //   "Account has been created.",
          //   Colors.green,
          // );
        } else {
          showSnackMessage(
            context,
            "Something went wrong. Try again letter.",
            Colors.red,
          );
        }
      }
    } finally {
      isLoading = false;
      update();
    }
  }

  void signupClear() {
    emailTextEditingControler.clear();
    firstNameTextEditingControler.clear();
    lastNameTextEditingControler.clear();
    passwordTextEditingControler.clear();

    phoneTextEditingControler.clear();
  }

  @override
  void dispose() {
    emailTextEditingControler.dispose();
    firstNameTextEditingControler.dispose();
    lastNameTextEditingControler.dispose();
    passwordTextEditingControler.dispose();
    phoneTextEditingControler.dispose();
    super.dispose();
  }
}

════════ Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown while finalizing the widget tree:
Duplicate GlobalKey detected in widget tree.
The following GlobalKey was specified multiple times in the widget tree. This will lead to parts of the widget tree being truncated unexpectedly, because the second time a key is seen, the previous instance is moved to the new location. The key was:
- [LabeledGlobalKey<FormState>#207b9 _home]
This was determined by noticing that after the widget with the above global key was moved out of its previous parent, that previous parent never updated during this frame, meaning that it either did not update at all or updated before the widget was moved, in either case implying that it still thinks that it should have a child with that global key.
The specific parent that did not update after having one or more children forcibly removed due to GlobalKey reparenting is:
- Column(direction: vertical, mainAxisAlignment: center, crossAxisAlignment: start, dependencies: [Directionality], renderObject: RenderFlex#14950 relayoutBoundary=up13 NEEDS-PAINT)
A GlobalKey can only be specified on one widget at a time in the widget tree.

I think i have found the problem but cannot figure out how do i solve the issue. Get.back() is working fine. I'm using GetX and running on Flutter 3.19.0.

Please help me to resolve this issue


Solution

  • Prolem Fixed! I was using both navigator.of and get at the same time.

    Like i was navigating to signup page using Navigator.of and try to get.off when sign up success. This was the reason behind the error.