You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

问题原因及修复方案

原因分析

无限循环的核心逻辑链是:

  1. 在onInputValidated回调中调用setState,更新了number变量和phoneNumberIsValid状态
  2. InternationalPhoneNumberInput组件的initialValue绑定了number变量,状态更新触发组件重建时,组件会重新读取initialValue
  3. 读取新的initialValue会触发输入内容的变更逻辑,进而再次调用onInputChanged和onInputValidated
  4. 上述步骤反复执行,形成无限循环

另外,你在onInputValidated里重复赋值this.number = number是多余的——onInputChanged已经在用户输入时同步更新了这个变量。

修复方案

修改onInputValidated回调,只更新phoneNumberIsValid状态,去掉对number变量的赋值:

onInputValidated: (bool value) {
  setState(() {
    phoneNumberIsValid = value;
  });
},

这样修改后,只有当验证状态(有效/无效)发生变化时才会触发setState,不会因为重复更新number变量导致组件反复触发输入回调,彻底解决无限循环问题。

内容的提问来源于stack exchange,提问作者Zorgan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 11:00:46