Home > Net >  How to use HookWidget with useTextEditingController
How to use HookWidget with useTextEditingController

Time:11-03

I'm new to flutter development and trying to understand Riverpod.

I currently managed to make the following login form work with a StatefulWidget. Basically, the button becomes enabled if both fields are not empty and viceversa.

enter image description here

And this is the current code for it.

import 'package:flutter/material.dart';

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

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Login Demo',
      // theme: ThemeData(
      //   primarySwatch: Colors.blue,
      // ),
      home: Scaffold(
        body: Center(
          child: SizedBox(
            width: 400,
            child: MyLoginPage2(),
          ),
        ),
      ),
    );
  }
}

class MyLoginPage extends StatefulWidget {
  const MyLoginPage({Key? key}) : super(key: key);

  @override
  State<MyLoginPage> createState() => _MyLoginState();
}

class _MyLoginState extends State<MyLoginPage> {
  final emailController = TextEditingController(text: '');
  final passwordController = TextEditingController(text: '');

  @override
  void initState() {
    super.initState();
    emailController.addListener(() {
      setState(() {});
    });
    passwordController.addListener(() {
      setState(() {});
    });
  }

  @override
  void dispose() {
    emailController.dispose();
    passwordController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        TextField(
          controller: emailController,
          keyboardType: TextInputType.emailAddress,
        ),
        TextField(
          controller: passwordController,
          obscureText: true,
        ),
        areFieldsEmpty()
            ? const ElevatedButton(
                child: Text('Login disabled'),
                onPressed: null,
              )
            : ElevatedButton(
                child: const Text('Login enabled'),
                onPressed: () => print("this is where login happens"),
              )
      ],
    );
  }

  bool areFieldsEmpty() {
    return emailController.text.toString().isEmpty ||
        passwordController.text.toString().isEmpty;
  }
}

What I don't like is how the listeners call setState directly just to trigger a widget refresh. Is this how would you accomplish such a behavior?

I read great things about Riverpod, but I don't seem to grasp how to model the above behavior inheriting from HookWidget instead of StatefulWidget. Specifically, how to add the listeners to the text editing controllers.

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';

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

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Login Demo',
      // theme: ThemeData(
      //   primarySwatch: Colors.blue,
      // ),
      home: Scaffold(
        body: Center(
          child: SizedBox(
            width: 400,
            child: MyLoginPage2(),
          ),
        ),
      ),
    );
  }
}

class MyLoginPage2 extends HookWidget {
  final emailController = useTextEditingController(text: '');
  final passwordController = useTextEditingController(text: '');

  MyLoginPage2({Key? key}) : super(key: key);

  // Pending questions
  // 1. Where do I add the listeners to the controllers?
  // 2. They are supposed to be auto dispose, right?

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        TextField(
          controller: emailController,
          keyboardType: TextInputType.emailAddress,
        ),
        TextField(
          controller: passwordController,
          obscureText: true,
        ),
        areFieldsEmpty()
            ? const ElevatedButton(
                child: Text('Login disabled'),
                onPressed: null,
              )
            : ElevatedButton(
                child: const Text('Login enabled'),
                onPressed: () => print("this is where login happens"),
              )
      ],
    );
  }

  bool areFieldsEmpty() {
    return emailController.text.toString().isEmpty ||
        passwordController.text.toString().isEmpty;
  }
}

Any help or tips will be appreciated.

CodePudding user response:

To update the changes on HookWidget use useEffect(). We don't have to worry about dispose until create our custom hookWidget.


class MyLoginPage2 extends HookWidget {
  const MyLoginPage2({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final emailController = useTextEditingController(text: '');
    final passwordController = useTextEditingController(text: '');

    final _areFieldsEmpty =
        useState<bool>(true); // controll the button based on Text.isEmpty

    bool areFieldsEmpty() {
      return emailController.text.toString().isEmpty ||
          passwordController.text.toString().isEmpty;
    }

    useEffect(() {
      emailController.addListener(() {
        _areFieldsEmpty.value = areFieldsEmpty();
      });
      passwordController.addListener(() {
        _areFieldsEmpty.value = areFieldsEmpty();
      });
    }, [
      emailController,
      passwordController,
    ]);
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        TextField(
          controller: emailController,
          keyboardType: TextInputType.emailAddress,
        ),
        TextField(
          controller: passwordController,
          obscureText: true,
        ),
        _areFieldsEmpty.value
            ? const ElevatedButton(
                child: Text('Login disabled'),
                onPressed: null,
              )
            : ElevatedButton(
                child: const Text('Login enabled'),
                onPressed: () => print("this is where login happens"),
              )
      ],
    );
  }
}


  • Related