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

如何用Riverpod结合API实现DropdownButtonFormField?代码报错求助

问题分析与修复方案

你的代码存在几个关键问题导致运行出错,以下是具体问题和修复后的完整代码:

存在的问题

  • _formKey未定义:Form组件需要GlobalKey<FormState>管理状态,但代码中未声明
  • 异步数据处理错误:ref.watch(kandangProvider).getKandang()如果是异步方法,直接调用会返回Future对象,无法直接遍历生成下拉选项
  • 数据源引用错误:DropdownButtonFormField的items里错误使用value.kandang,这里的value是onChanged的回调参数,并非从Provider获取的数据源
  • 缺少状态处理:未处理API请求的加载、错误状态,直接渲染会引发空指针或异常

修复后的代码

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

// 假设你的Kandang数据模型
class KandangModel {
  final String kode_kandang;
  KandangModel({required this.kode_kandang});
}

// 假设kandangProvider是用于获取Kandang列表的FutureProvider
final kandangProvider = FutureProvider<List<KandangModel>>((ref) async {
  // 替换为你的实际API请求逻辑
  await Future.delayed(const Duration(seconds: 1));
  return [
    KandangModel(kode_kandang: "K001"),
    KandangModel(kode_kandang: "K002"),
    KandangModel(kode_kandang: "K003"),
  ];
});

class MyDropdownButton extends StatelessWidget {
  // 声明Form全局状态key
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    // 监听kandangProvider,获取异步状态数据
    final kandangAsyncValue = ref.watch(kandangProvider);

    return SingleChildScrollView(
      child: LimitedContainer(
        limitWidth: maxScreenWidth,
        child: BackStack(
          showBackButton: true,
          children: [
            Container(
              alignment: Alignment.center,
              child: Form(
                key: _formKey,
                child: SingleChildScrollView(
                  padding: const EdgeInsets.all(formPadding),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: <Widget>[
                      const SizedBox(height: 5),
                      Container(
                        width: 400,
                        height: 60,
                        margin: const EdgeInsets.only(top: 20),
                        // 处理异步数据的三种状态:加载、错误、数据就绪
                        child: kandangAsyncValue.when(
                          loading: () => const Center(child: CircularProgressIndicator()),
                          error: (error, stack) => Text('加载失败: $error'),
                          data: (kandangList) {
                            return DropdownButtonFormField<String>(
                              decoration: kTextFiledInputDecoration.copyWith(
                                labelText: "Kode Kandang",
                              ),
                              onChanged: (selectedValue) {
                                print('选中的值: $selectedValue');
                                // 若需更新其他Provider状态,使用ref.read
                                // ref.read(targetProvider.notifier).update(selectedValue);
                              },
                              items: kandangList.map<DropdownMenuItem<String>>((kandang) {
                                return DropdownMenuItem(
                                  value: kandang.kode_kandang,
                                  child: Text(kandang.kode_kandang),
                                );
                              }).toList(),
                            );
                          },
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// 假设你已定义以下常量与组件
const double maxScreenWidth = 600;
const double formPadding = 16;
final kTextFiledInputDecoration = InputDecoration(
  border: OutlineInputBorder(),
);

class LimitedContainer extends StatelessWidget {
  final double limitWidth;
  final Widget child;
  const LimitedContainer({required this.limitWidth, required this.child, super.key});

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: MediaQuery.of(context).size.width > limitWidth ? limitWidth : double.infinity,
        child: child,
      ),
    );
  }
}

class BackStack extends StatelessWidget {
  final bool showBackButton;
  final List<Widget> children;
  const BackStack({required this.showBackButton, required this.children, super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        if (showBackButton)
          ElevatedButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('返回'),
          ),
        ...children,
      ],
    );
  }
}

关键修复说明

  1. 添加Form全局key:声明_formKey用于管理Form组件状态
  2. 异步状态处理:通过ref.watch(kandangProvider)获取AsyncValue,用when方法分别处理加载、错误、数据就绪三种状态
  3. 数据源正确引用:在data回调中使用从Provider获取的kandangList生成下拉选项,避免混淆onChanged的参数
  4. 状态更新逻辑:选中选项后若需更新其他状态,使用ref.read(provider.notifier)执行操作,避免在build方法中产生副作用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:10:50