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

Flutter中DropdownButtonFormField调用setState后UI不更新问题

问题根源

你的DefaultDropdown组件内部维护了_currentValue状态,但仅在initState时初始化,当父组件更新传入的initialValue(即通过CEP获取到新的UF值时),子组件没有同步这个新值,导致Dropdown的UI还是显示旧值。只有当PageView切换页面触发组件重建时,才会重新获取最新的initialValue,这就是切换页面后才显示正确值的原因。

解决方案

1. 修复DefaultDropdown组件的状态同步

在DefaultDropdownState中重写didUpdateWidget方法,当父组件传入的initialValue发生变化时,同步更新内部的_currentValue并触发UI刷新:

@override
void didUpdateWidget(covariant DefaultDropdown<T> oldWidget) {
  super.didUpdateWidget(oldWidget);
  // 当初始值变化时,同步更新内部状态
  if (widget.initialValue != oldWidget.initialValue) {
    setState(() {
      _currentValue = widget.initialValue;
    });
  }
}

完整修改后的DefaultDropdownState代码:

class DefaultDropdownState<T> extends State<DefaultDropdown<T>> {
  T? _currentValue;

  @override
  void initState() {
    super.initState();
    _currentValue = widget.initialValue;
  }

  // 添加该方法处理父组件参数更新
  @override
  void didUpdateWidget(covariant DefaultDropdown<T> oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.initialValue != oldWidget.initialValue) {
      setState(() {
        _currentValue = widget.initialValue;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          widget.label,
          style: const TextStyle(fontWeight: FontWeight.w800),
        ),
        const SizedBox(height: 8),
        SizedBox(
          height: widget.height,
          child: DropdownButtonFormField<T>(
            value: _currentValue,
            onChanged: (newValue) {
              setState(() {
                _currentValue = newValue;
                widget.onChanged(newValue);
              });
            },
            decoration: InputDecoration(
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(8),
              ),
              fillColor: widget.fillColor,
              filled: true,
              contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
            ),
            isExpanded: true,
            items: widget.items.map((T item) {
              return DropdownMenuItem<T>(
                value: item,
                child: Text(
                  item.toString(),
                  overflow: TextOverflow.ellipsis,
                ),
              );
            }).toList(),
          ),
        ),
      ],
    );
  }
}

2. 确认CompanyFormThree的状态绑定正确

确保CompanyFormThree中的UF状态正确关联父组件传入的值:

  • 将组件内的UF变量改为状态变量(比如late String _uf)
  • 在initState中初始化_uf = widget.uf
  • 在_fetchAddressFromCEP的setState中更新_uf,同时调用widget.onUfChanged同步到父页面

修改后的CompanyFormThree关键代码示例:

class CompanyFormThree extends StatefulWidget {
  final ValueChanged<String> onUfChanged;
  final String uf;
  // 其他参数...

  const CompanyFormThree({
    super.key,
    required this.onUfChanged,
    required this.uf,
    // 其他参数初始化...
  });

  @override
  State<CompanyFormThree> createState() => _CompanyFormThreeState();
}

class _CompanyFormThreeState extends State<CompanyFormThree> {
  late String _uf;
  // 其他控制器...

  @override
  void initState() {
    super.initState();
    _uf = widget.uf;
    // 其他初始化代码...
  }

  void _fetchAddressFromCEP(String cep) async {
    final response = await http.get(Uri.parse('https://viacep.com.br/ws/$cep/json/'));

    if (response.statusCode == 200) {
      final data = jsonDecode(response.body);

      if (data['erro'] == null) {
        if(mounted){
          setState(() {
            publicSpaceController.text = data['logradouro'] ?? '';
            neighborhoodController.text = data['bairro'] ?? '';
            cityController.text = data['localidade'] ?? '';
            numberController.text = ''; 
            _uf = data['uf'] ?? ''; 
            widget.onUfChanged(_uf);
          });
        }
      } else {
        AlertSnackBar.show(context: context, text: "CEP não encontrado.");
      }
    } else {
      AlertSnackBar.show(context: context, text: "Erro ao buscar CEP.");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        children: [
          // 其他组件...
          DefaultDropdown(
            items: ufsBrasil,
            label: "UF",
            initialValue: _uf.isNotEmpty ? _uf : null,
            onChanged: (newUF) {
              setState(() {
                _uf = newUF!;
              });
              widget.onUfChanged(_uf);
            },
          ),
          // 其他组件...
        ],
      ),
    );
  }
}
原理说明
  • didUpdateWidget是StatefulWidget的生命周期方法,当父组件传入的参数变化时会被调用,通过对比新旧initialValue,可以同步更新子组件内部的状态。
  • 确保子组件的状态和父组件的状态双向绑定,无论是用户手动选择Dropdown还是通过API自动填充,都能实时同步并刷新UI。

内容的提问来源于stack exchange,提问作者Daniel Henrique Hartmann

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 05:22:34