Flutter中如何使用HookWidget与useTextEditingController实现登录表单功能
实现方案优化

疑问解答
useTextEditingController会自动完成销毁逻辑,所有flutter_hooks提供的内置Hook都封装了生命周期管理,不需要手动调用dispose。- 所有
use开头的Hook方法必须写在build方法内部,不能作为类的属性初始化,你的现有写法是错误的,类属性只会在实例化时执行一次,会触发Hook使用规则异常。
Flutter Hooks 正确实现
无需手动添加监听、无需调用setState,通过useListenable监听输入框变化触发局部重绘,性能优于全页面刷新的StatefulWidget方案:
import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Login Demo', home: Scaffold( body: Center( child: SizedBox( width: 400, child: MyLoginPage2(), ), ), ), ); } } class MyLoginPage2 extends HookWidget { MyLoginPage2({super.key}); @override Widget build(BuildContext context) { // Hook必须在build内部初始化 final emailController = useTextEditingController(text: ''); final passwordController = useTextEditingController(text: ''); // 监听两个输入框的状态变化 useListenable(emailController); useListenable(passwordController); final isLoginEnabled = emailController.text.isNotEmpty && passwordController.text.isNotEmpty; return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextField( controller: emailController, keyboardType: TextInputType.emailAddress, decoration: const InputDecoration(hintText: '邮箱'), ), TextField( controller: passwordController, obscureText: true, decoration: const InputDecoration(hintText: '密码'), ), const SizedBox(height: 20), ElevatedButton( onPressed: isLoginEnabled ? () => print("登录逻辑执行") : null, child: Text(isLoginEnabled ? '登录可用' : '登录禁用'), ) ], ); } }
Riverpod 实现方案(更适合复杂表单场景)
状态完全脱离Widget生命周期管理,后续扩展表单校验、状态共享等需求更灵活:
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; void main() { runApp(const ProviderScope(child: MyApp())); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Login Demo', home: Scaffold( body: Center( child: SizedBox( width: 400, child: MyLoginPage(), ), ), ), ); } } // 定义表单状态Provider final emailProvider = StateProvider<String>((ref) => ''); final passwordProvider = StateProvider<String>((ref) => ''); // 派生登录按钮可用状态 final isLoginEnabledProvider = Provider<bool>((ref) { final email = ref.watch(emailProvider); final password = ref.watch(passwordProvider); return email.isNotEmpty && password.isNotEmpty; }); class MyLoginPage extends ConsumerWidget { const MyLoginPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextField( keyboardType: TextInputType.emailAddress, decoration: const InputDecoration(hintText: '邮箱'), onChanged: (value) => ref.read(emailProvider.notifier).state = value, ), TextField( obscureText: true, decoration: const InputDecoration(hintText: '密码'), onChanged: (value) => ref.read(passwordProvider.notifier).state = value, ), const SizedBox(height: 20), ElevatedButton( onPressed: ref.watch(isLoginEnabledProvider) ? () => print("登录逻辑执行") : null, child: Text(ref.watch(isLoginEnabledProvider) ? '登录可用' : '登录禁用'), ) ], ); } }
内容的提问来源于stack exchange,提问作者Robert Estivill
相关产品推荐
相关产品推荐

