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.
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"),
)
],
);
}
}