Flutter Riverpod环境下选择国家后phoneCode无法界面更新问题
问题修复:Flutter Riverpod 选中国家后界面不更新
核心问题分析
- 未同步更新全局状态:
LoginPage的pickCountry方法里仅修改了局部变量currentCountry,没有通过Riverpod的notifier更新countryProvider的全局状态,导致界面感知不到变化。 - 错误的状态监听逻辑:
CountryCodeAndTextField中监听countryProvider.notifier并取其state,这种方式不会触发Widget重建,应该直接监听countryProvider本身。 - 异步代码执行顺序错误:
debugPrint放在showCountryPicker外部,会在用户选择国家前执行,打印的是旧值而非选中后的最新值。
修复后的代码
1. 修正 login_page.dart
class LoginPage extends ConsumerWidget { const LoginPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { void pickCountry() { showCountryPicker( context: context, onSelect: (Country selectedCountry) { // 关键:通过notifier更新provider的全局状态 ref.read(countryProvider.notifier).state = selectedCountry; // 在回调内打印才能获取选中后的最新值 debugPrint('selected phone code: ${selectedCountry.phoneCode}'); }, ); } return Scaffold( appBar: AppBar( centerTitle: true, title: const Text( 'Enter your phone number', style: TextStyle( color: Colors.white, ), ), ), body: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ const Text( 'Chattor will need to verify your phone number', style: TextStyle(color: Colors.grey), ), TextButton( onPressed: pickCountry, child: const Text( 'Pick Country', style: TextStyle(color: Colors.amber), ), ), const CountryCodeAndTextField(), SizedBox(height: ScreenSize.getHeight(context) * 0.63), SizedBox( width: ScreenSize.getWidth(context) * 0.30, height: ScreenSize.getHeight(context) * 0.07, child: const NextButtonWidget(), ), ], ), ); } }
2. 修正 country_code_and_text_field.dart
class CountryCodeAndTextField extends ConsumerWidget { const CountryCodeAndTextField({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { // 直接监听countryProvider,状态变化时自动触发Widget重建 final Country? country = ref.watch(countryProvider); // TextEditingController用read而非watch,避免不必要的重建 final phoneController = ref.read(phoneControllerProvider); return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ if (country != null) Text( '+${country.phoneCode}', style: const TextStyle(color: Colors.white), ) else const Text( '00', style: TextStyle(color: Colors.white), ), SizedBox( width: ScreenSize.getWidth(context) * 0.6, child: TextField( controller: phoneController, decoration: const InputDecoration( hintText: 'Enter your phone number', hintStyle: TextStyle(color: Colors.grey), ), ), ), ], ); } }
额外优化建议
phoneControllerProvider无需用StateProvider包裹,因为TextEditingController本身是可变对象,改用Provider并添加销毁逻辑更合理:
final phoneControllerProvider = Provider<TextEditingController>((ref) { final controller = TextEditingController(); // 页面销毁时释放控制器,避免内存泄漏 ref.onDispose(() => controller.dispose()); return controller; });
内容的提问来源于stack exchange,提问作者OGY
相关产品推荐
相关产品推荐

