Flutter Stateful Widget传值为null、ModalRoute传参偶发失效求助
问题排查及修复方案
核心问题1:TextFormField参数冲突
你自定义的EditTextFieldForm中同时给TextFormField设置了controller和initialValue,这是Flutter明确禁止的写法,二者只能选其一。要设置初始值直接在初始化TextEditingController时赋值即可,不需要再传initialValue参数,这是你报错的高频触发原因。
核心问题2:路由参数取值逻辑错误
ModalRoute.of(context).settings.arguments是同步获取的,不需要用await包裹,你把它包装成异步Future的写法完全错误,也是你后续FutureBuilder报错的直接原因。另外你直接用as String强转参数,一旦参数为空或者类型不匹配就会直接抛出空异常。
修复取值逻辑如下:
final dynamic args = ModalRoute.of(context)?.settings.arguments; // 先做非空和类型校验 if (args == null || args is! String) { return Scaffold( body: Center(child: Text('无效的页面参数,即将返回')), ); } final _deedID = args as String;
同时请校验你跳转页面的代码是否正确传参:
Navigator.pushNamed( context, EditDashboardCardDetailsScreen.routeName, arguments: '实际要传递的deedID字符串', // 确保这里传值且是String类型 );
核心问题3:Provider数据加载时机不一致
你时好时坏的问题本质是Provider.of<DeedsData>(context).findByKey(_deedID)的执行时机和DeedsData的数据加载时机不匹配:页面build的时候如果Provider的数据还没加载完成,拿到的_loadedDeed就会是null,自然它的title也是null。
修复方案是用Consumer监听DeedsData的状态,等数据加载完成再渲染表单:
class EditDashboardCardDetailsScreen extends StatelessWidget { static const routeName = '/EditDashboardDetail'; @override Widget build(BuildContext context) { final dynamic args = ModalRoute.of(context)?.settings.arguments; if (args == null || args is! String) { return Scaffold(body: Center(child: Text('参数错误'))); } final _deedID = args; return Scaffold( body: SafeArea( child: CustomScrollView( slivers: [ SliverAppBar( pinned: true, expandedHeight: 250.0, flexibleSpace: FlexibleSpaceBar( title: Text("Edit space"), ), ), // 用Consumer监听DeedsData变化 Consumer<DeedsData>( builder: (context, deedsData, child) { final _loadedDeed = deedsData.findByKey(_deedID); // 数据为空时展示加载态 if (_loadedDeed == null) { return const SliverToBoxAdapter( child: Center(child: CircularProgressIndicator()), ); } // 数据加载完成后初始化controller并渲染表单 final _textCtrlA = TextEditingController(text: _loadedDeed.title ?? ''); return SliverList( delegate: SliverChildListDelegate( [ EditTextFieldForm( labelText: "Title", maxLines: 3, textControllerTextForm: _textCtrlA, ), ], ), ); }, ) ], ), ), ); } } // 复用组件删掉initialValue相关代码 class EditTextFieldForm extends StatefulWidget { final String labelText; final TextEditingController textControllerTextForm; final int maxLines; EditTextFieldForm({ @required this.labelText, @required this.textControllerTextForm, @required this.maxLines, }); @override _EditTextFieldFormState createState() => _EditTextFieldFormState(); } class _EditTextFieldFormState extends State<EditTextFieldForm> { @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.all(12), child: TextFormField( controller: widget.textControllerTextForm, maxLines: widget.maxLines, decoration: InputDecoration( labelText: widget.labelText, focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(5.0)), borderSide: BorderSide(color: Colors.blue), ), ), ), ); } }
其他问题补充
你之前写的FutureBuilder还有一个语法错误:builder函数的else分支只声明了Center组件没有return,Flutter要求builder必须返回Widget,缺少return也会触发空返回异常。
你原本从Stateless Widget向内部Stateful Widget传值的写法本身没有问题,只要确保传入的参数非空即可。
内容的提问来源于stack exchange,提问作者HanYee

