i have some questions about which is the correct way of creating TexEditingController;

Assuming that i want to create a controller with a fixed text, so i can do like this :

TextEditingController bioEditorController = new TextEditingController(text:"dummy");

Now my questions is this:

if i'm usign a stateful widget i can create this controller ad assign an initial text by doing this :

TextEditingController bioEditorController;

@override
void initState() {
  bioEditorController = new TextEditingController(text: "dummy");
  super.initState();
}

but if i'm not using a stateful widget is it correct to make something like this :

@override
Widget build(BuildContext context) {
 TextEditingController bioEditorController =
    new TextEditingController(text: controller.profile.value.bio);

What i mean is it correct to create this controller inside the build method, if i do like this it works , but i think that probably is not the best way of doing this things, also becauze i know that controller should also disposed....

I really need some help about clarifying this. Thanks


Solution 1: Loren.A

You are correct in assuming that doing that in the build method is not ideal. You have way less control over how many times the build method runs vs initState.

And while it's generally true that you would need a stateful widget when dealing with TextEditingControllers (or hooks), if you use GetX state management it's absolutely fine, and preferred to not bother with a stateful widget just because you need a TextEditingController.

Another benefit of this way is very easy access to the value of the TextEditingController from anywhere else in the app.

Here's a quick example. This is a class where you can keep all your TextEditingControllers.

class TextController extends GetxController {
  RxString textfieldString = ''.obs; // observable String

  TextEditingController textController;

// this onInit replaces initState of a stateful widget
  @override
  onInit() {
    super.onInit();
    textController = TextEditingController(text: 'dummy');

// adding a listener that automatically updates the textfieldString with the textfield value

    textController.addListener(() {
      textfieldString.value = textController.text;
      debugPrint(textfieldString.value);
    });
  }
}

Initialize the controller in your main or anytime before you actually use it. This is when the onInit from that class is called.

Get.put(TextController()).textController;

Here's Page1 a stateless widget with an already initialized TextEditingController

class Page1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final controller = Get.find<TextController>(); // finding same initialized controller
    return Scaffold(
      body: Center(
        child: TextFormField(
          controller: controller.textController, // using TextEditingConroller from GetX class
        ),
      ),
    );
  }
}

And here's a quick example of a text widget on a different page automatically updating anytime the user types into the TextFormField

class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final controller =
        Get.find<TextController>(); // finding same instance of controller
    return Scaffold(
      body: Center(
        // this Obx widget rebuilds based on any updates
        child: Obx(
          () => Text(controller.textfieldString.value),
        ),
      ),
    );
  }
}

So no matter where you are in your app, you can access the value of that TextFormField and you don't have to use a stateful widget. The GetxController will be removed from memory when not in use.

At this point the only time I ever need to use a stateful widget is when I need the AutomaticKeepAliveClientMixin.

Even animations can be done with stateless widgets in GetX by adding SingleGetTickerProviderMixin to a Getx class and doing everything there that would normally clutter up your stateful widget.