如何用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, ], ); } }
关键修复说明
- 添加Form全局key:声明
_formKey用于管理Form组件状态 - 异步状态处理:通过
ref.watch(kandangProvider)获取AsyncValue,用when方法分别处理加载、错误、数据就绪三种状态 - 数据源正确引用:在data回调中使用从Provider获取的
kandangList生成下拉选项,避免混淆onChanged的参数 - 状态更新逻辑:选中选项后若需更新其他状态,使用
ref.read(provider.notifier)执行操作,避免在build方法中产生副作用
内容的提问来源于stack exchange,提问作者AqFamous
相关产品推荐
相关产品推荐

