Flutter多选组件报错:setState() called after dispose()
问题分析
出现setState() called after dispose()错误的核心原因:
- FutureBuilder重复创建Future:每次父组件触发
setState(比如普通下拉选择时),FutureBuilder都会重新调用Provider.of<Salesmans>(context, listen: false).getUser()生成新Future,导致旧的MultiSelectField被销毁。 - 多选对话框回调关联已销毁组件:如果此时多选对话框仍处于打开状态,确认选择时的
onConfirm回调会试图操作已销毁的组件状态,触发错误。 - 额外冗余:普通下拉的
onChanged中存在无意义的_selectedRoles;代码,可直接删除。
解决方案
1. 缓存Future避免重复执行
将获取用户的Future存储在父组件状态中,确保FutureBuilder只执行一次:
// 父组件State类中添加变量 Future<Salesman> _userFuture; @override void initState() { super.initState(); // 在initState中初始化Future,避免每次build重复调用 _userFuture = Provider.of<Salesmans>(context, listen: false).getUser(); } // 替换原有FutureBuilder FutureBuilder( future: _userFuture, // 使用缓存的Future builder: (BuildContext context, AsyncSnapshot<Salesman> snapshot) { // 原有逻辑保持不变 if (snapshot.connectionState == ConnectionState.done) { return MultiSelectField<DdlValues>( // ... 其他属性 ); } else { return CircularProgressIndicator(); } }, ),
2. 给MultiSelectField添加稳定Key
设置固定Key,确保父组件重建时,该组件不会被销毁重建,而是更新现有实例:
// 父组件State类中定义Key final _multiSelectKey = GlobalKey<MultiSelectFieldState<DdlValues>>(); // 在MultiSelectField中使用该Key return MultiSelectField<DdlValues>( key: _multiSelectKey, initialValue: _selectedRoles, buttonText: 'Select Roles', title: 'Select Roles', stream: _listRoles, onConfirm: (values) { // 确保父组件仍挂载时再更新状态 if (mounted) { setState(() { _selectedRoles = values; }); } }, );
3. 完善MultiSelectField的状态安全
在自定义MultiSelectField中,确保回调仅在组件挂载时执行:
// 修改MultiSelectField中的MultiSelectDialogField配置 return MultiSelectDialogField( buttonText: Text(widget.buttonText), title: Text(widget.title), items: widget.stream .map((item) => MultiSelectItem(item, item.name)) .toList(), initialValue: widget.initialValue, onConfirm: (values) { // 检查当前组件是否仍挂载 if (mounted) { widget.onConfirm(values); } }, listType: MultiSelectListType.LIST, validator: (List value) { if (value?.isEmpty ?? true) { return 'Please select Roles '; } return null; }, );
4. 清理冗余代码
删除普通下拉onChanged中的无意义代码:
onChanged: (String value) { if (mounted) { setState(() { dropdownValueLvl = value; // 移除该行:_selectedRoles; }); } },
验证效果
完成上述修改后,父组件触发setState时,FutureBuilder不会重新创建MultiSelectField,多选对话框的回调只会关联活跃的组件实例,从而避免setState() called after dispose()错误。
内容的提问来源于stack exchange,提问作者Altaf Shaikh
相关产品推荐
相关产品推荐

