Flutter中调用setState引发无限build循环问题求助
问题:intl_phone_number_input包触发onInputValidated无限循环
我在登录表单中使用intl_phone_number_input Flutter包实现手机号验证功能,需求是当输入的手机号验证通过时,将“CONTINUE”按钮设置为可点击状态。但实际运行时出现无用户交互情况下onInputValidated被无限调用的问题。
我的代码
class Otp extends Stateful Widget { const Otp({Key? key}) : super(key: key); @override State<Otp> createState() => _OtpState(); } class _OtpState extends State<Otp> { final GlobalKey<FormState> formKey = GlobalKey<FormState>(); final phoneNumberController = TextEditingController(); final otpController = TextEditingController(); late String initialCountry; late PhoneNumber number; String validNumber = ""; bool phoneNumberIsValid = false; FirebaseAuth auth = FirebaseAuth.instance; late String verificationId; bool otpCodeSent = false; @override void initState() { String locale = Platform.localeName; print("Platform locale: ${Platform.localeName.substring(locale.length - 2, locale.length)}"); String countryCode = Platform.localeName.substring(locale.length - 2, locale.length); number = PhoneNumber(isoCode: countryCode); super.initState(); } @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(30.0), child: otpCodeSent ? otpColumn() : Form( key: formKey, child: Container( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ InternationalPhoneNumberInput( onInputChanged: (PhoneNumber number) { this.number = number; print("Input changed to: ${number.phoneNumber}"); }, onInputValidated: (bool value) { if (value == true){ print("onInputValidated number: ${number.phoneNumber}"); setState(() { this.number = number; phoneNumberIsValid = true; }); print("onInputValidated number: ${number.phoneNumber}"); } }, selectorConfig: SelectorConfig( selectorType: PhoneInputSelectorType.BOTTOM_SHEET, ), ignoreBlank: false, autoValidateMode: AutovalidateMode.disabled, selectorTextStyle: TextStyle(color: Colors.black), initialValue: number, textFieldController: phoneNumberController, formatInput: false, keyboardType: TextInputType.numberWithOptions(signed: true, decimal: true), ), Padding(padding: EdgeInsets.only(bottom: 30)), ElevatedButton( onPressed: !phoneNumberIsValid ? null : () async { String? phoneNumber = number.phoneNumber; print("Phone number is: $phoneNumber"); if (phoneNumber == null){ return;} if (phoneNumberIsValid){ print("VALID NUMBER, SEND CODE"); _verifyPhoneNumber(phoneNumber: phoneNumber); } else { print("INVALID NUMBER, COULD NOT SEND CODE"); } }, child: Opacity( opacity: phoneNumberIsValid ? 1 : 0.4, child: RowButton("CONTINUE", Icons.arrow_forward_sharp) ), ), ], ), ), ), ); } }
日志输出
I/flutter (26758): Input changed to: +XXXXXXXXXX I/flutter (26758): onInputValidated number: +XXXXXXXXXX I/flutter (26758): onInputValidated number: +XXXXXXXXXX I/flutter (26758): Input changed to: +XXXXXXXXXX I/flutter (26758): onInputValidated number: +XXXXXXXXXX I/flutter (26758): onInputValidated number: +XXXXXXXXXX I/flutter (26758): Input changed to: +XXXXXXXXXX I/flutter (26758): onInputValidated number: +XXXXXXXXXX I/flutter (26758): onInputValidated number: +XXXXXXXXXX I/flutter (26758): Input changed to: +XXXXXXXXXX I/flutter (26758): onInputValidated number: +XXXXXXXXXX I/flutter (26758): onInputValidated number: +XXXXXXXXXX I/flutter (26758): Input changed to: +XXXXXXXXXX I/flutter (26758): onInputValidated number: +XXXXXXXXXX I/flutter (26758): onInputValidated number: +XXXXXXXXXX
问题原因及修复方案
原因分析
无限循环的核心逻辑链是:
- 在
onInputValidated回调中调用setState,更新了number变量和phoneNumberIsValid状态 InternationalPhoneNumberInput组件的initialValue绑定了number变量,状态更新触发组件重建时,组件会重新读取initialValue- 读取新的
initialValue会触发输入内容的变更逻辑,进而再次调用onInputChanged和onInputValidated - 上述步骤反复执行,形成无限循环
另外,你在onInputValidated里重复赋值this.number = number是多余的——onInputChanged已经在用户输入时同步更新了这个变量。
修复方案
修改onInputValidated回调,只更新phoneNumberIsValid状态,去掉对number变量的赋值:
onInputValidated: (bool value) { setState(() { phoneNumberIsValid = value; }); },
这样修改后,只有当验证状态(有效/无效)发生变化时才会触发setState,不会因为重复更新number变量导致组件反复触发输入回调,彻底解决无限循环问题。
内容的提问来源于stack exchange,提问作者Zorgan
相关产品推荐
相关产品推荐

