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

API返回数据后DropdownButtonFormField2的UI未更新问题求助

解决DropdownButtonFormField2在MobX下API数据返回后不更新的问题

核心问题

你的页面没有监听MobX中obsItemSpec的状态变化,虽然在API请求完成后调用了setState(),但这只是一次性触发重建,无法响应MobX状态的后续更新;切换页面再返回能刷新,是因为页面重新执行build方法时才读取到最新的obsItemSpec数据。

解决方案

1. 用MobX的Observer组件包裹下拉框

Observer会自动监听其builder函数内用到的Observable变量,当变量变化时自动重建内部Widget,无需手动调用setState()。

2. 优化Store中的Observable定义(可选但推荐)

将Observable<List<ItemSpec>?>改为ObservableList<ItemSpec>?,MobX的ObservableList对列表的增删改操作有更细粒度的监听支持,比普通的Observable<List>更适配列表场景。

修改后的代码

my_store.dart

part 'my_store.g.dart';

class MyStore = _MyStore with _$MyStore;

abstract class _MyStore with Store {
  @observable
  ObservableList<ItemSpec>? obsItemSpec;

  @action
  Future getItemList() async {
    final itemList = await _useCase.getItemList();
    obsItemSpec = ObservableList.of(
      itemList.map((list) => ItemSpec(list.name, list.id)).toList()
    );
  }
}

my_screen.dart

class MyScreenState extends State<MyScreen> {
  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async => false,
      child: Scaffold(
        key: _scaffoldKey,
        // 用Observer包裹下拉框,监听MobX状态变化
        body: Observer(
          builder: (_) => _buildItemDropDown(),
        ),
      ),
    );
  }

  @override
  void initState() {
    super.initState();
    // 直接调用API,无需手动setState
    _my_store.getItemList();
  }

  Widget _buildItemDropDown() {
    // 处理数据未加载完成的情况
    if (_my_store.obsItemSpec == null) {
      return const Center(child: CircularProgressIndicator());
    }

    return DropdownButtonHideUnderline(
      key: UniqueKey(),
      child: DropdownButtonFormField2(
        decoration: InputDecoration(
          isDense: true,
          contentPadding: EdgeInsets.zero,
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(4),
          ),
          focusedBorder: OutlineInputBorder(
              borderSide: BorderSide(color: ColorPalette.green[400]!)),
          enabledBorder: OutlineInputBorder(
              borderSide: BorderSide(color: ColorPalette.black[200]!)),
        ),
        isExpanded: true,
        hint: const Text(
          'Options',
          style: TextStyle(fontSize: 14),
        ),
        iconOnClick: SvgPicture.asset(
          'assets/svg/arrow_drop_down_activated.svg',
        ),
        icon: SvgPicture.asset(
          'assets/svg/arrow_drop_down.svg',
        ),
        iconSize: 30,
        isDense: true,
        buttonHeight: 40,
        buttonPadding: const EdgeInsets.only(left: 12, right: 12),
        dropdownDecoration: BoxDecoration(
          borderRadius: BorderRadius.circular(4),
        ),
        items: _my_store.obsItemSpec!.asMap().entries.map((item) {
          return DropdownMenuItem<String>(
            value: item.value,
            enabled: false,
            child: StatefulBuilder(
              builder: (context, menuSetState) {
                final _isSelected = selectedItems.contains(item.value);
                return InkWell(
                  onTap: () {
                    _isSelected
                        ? selectedItems.remove(item.value)
                        : selectedItems.add(item.value);
                    setState(() {});
                    menuSetState(() {});
                  },
                  child: Container(
                    color: (item.key % 2 != 0)
                        ? ColorPalette.white[400]
                        : ColorPalette.white[500],
                    height: double.infinity,
                    padding:
                        const EdgeInsets.symmetric(horizontal: 18.0, vertical: 0),
                    child: Row(
                      children: [
                        _isSelected
                            ? SvgPicture.asset(
                                'assets/svg/checkbox_green_outlined.svg',
                              )
                            : SvgPicture.asset(
                                'assets/svg/checkbox_outlined_blank.svg',
                              ),
                        const SizedBox(width: 10),
                        Text(
                          item.value,
                          style: const TextStyle(
                            fontSize: 14,
                          ),
                        ),
                      ],
                    ),
                  ),
                );
              },
            ),
          );
        }).toList(),
        itemPadding: EdgeInsets.zero,
        value: selectedItems.isEmpty ? null : selectedItems.last,
        validator: (value) {
          if (value == null) {
            return 'Please select gender.';
          }
        },
        onChanged: (value) {},
        selectedItemBuilder: (context) {
          return _my_store.obsItemSpec!.map(
            (item) {
              return Container(
                padding: const EdgeInsets.symmetric(horizontal: 0.0),
                child: Text(
                  selectedItems.join(', '),
                  style: const TextStyle(
                    fontSize: 14,
                    overflow: TextOverflow.ellipsis,
                  ),
                  maxLines: 1,
                ),
              );
            },
          ).toList();
        },
      ),
    );
  }
}

关键说明

  • Observer是MobX的核心组件,用于监听Observable变量变化,确保UI与状态同步。
  • 移除initState中getItemList()后的setState(),Observer会自动处理状态更新后的UI重建。
  • 添加数据加载状态判断,避免obsItemSpec为null时出现空指针异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 17:15:11