Flutter中Model类意外更新:如何阻止未保存时的数值修改?
解决Model类意外更新的问题
我帮你排查了代码里的问题,核心原因是Dart中自定义类属于引用类型:你直接把myNumber实例传给模态框时,模态框里的_newNumber和主页面的myNumber指向的是同一个对象内存地址——所以哪怕你没点保存,修改_newNumber.number的时候,原对象的数值也会跟着变。
修复方案:创建对象副本
我们需要在打开模态框时,创建原NumberClass对象的独立副本,让模态框操作副本,这样原对象就不会被意外修改,只有用户点击保存时,再用副本替换原对象。
修改后的完整代码
class MaterialScreen extends StatefulWidget { @override _MaterialScreenState createState() => _MaterialScreenState(); } NumberClass myNumber = NumberClass(0); class _MaterialScreenState extends State<MaterialScreen> { Widget build(BuildContext context) { return Scaffold( body: Center( child: FlatButton( child: Text('Open'), onPressed: () async { NumberClass n = await showModalBottomSheet( context: context, builder: (_) => Modal( number: myNumber, ), ); if (n != null) { setState(() { myNumber = n; }); } }, ), ), ); } } class Modal extends StatefulWidget { final NumberClass number; const Modal({this.number}); @override _ModalState createState() => _ModalState(); } class _ModalState extends State<Modal> { NumberClass _newNumber; // 把变量移到State类内部,避免全局变量污染 @override void initState() { // 关键:创建原对象的独立副本,而非直接赋值引用 _newNumber = NumberClass(widget.number.number); super.initState(); } @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text(_newNumber.number.toString()), FlatButton( child: Text('Update'), onPressed: () { setState(() { _newNumber.number = _newNumber.number + 1; }); print(_newNumber.number); print(widget.number.number); // 现在这里会保持原数值不变 }, ) ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[ OutlineButton( child: Text('close - dont save'), onPressed: () => Navigator.pop(context), ), OutlineButton( child: Text('close - save'), onPressed: () => Navigator.pop(context, _newNumber), ), ], ) ], ); } } class NumberClass { int number; NumberClass(this.number); // 可选扩展:添加copyWith方法,后续新增属性时更优雅地创建副本 NumberClass copyWith({int number}) { return NumberClass(number ?? this.number); } }
关键修改点说明
- 创建独立副本:在
Modal的initState里,我们用NumberClass(widget.number.number)生成了新实例,让_newNumber和原对象彻底独立,修改副本不会影响原对象。 - 移除全局变量:把
_newNumber移到_ModalState内部,避免全局变量带来的意外状态干扰。 - 可选copyWith方法:如果后续
NumberClass需要添加更多属性,用copyWith可以更简洁地创建副本,比如_newNumber = widget.number.copyWith()。
修改后,模态框内的操作只会影响副本:点击“close - save”才会用副本更新主页面,点击“close - dont save”则直接关闭,原数值完全保留,重新打开模态框时会再次基于原对象创建新副本,显示修改前的状态。
内容的提问来源于stack exchange,提问作者delmin
相关产品推荐
相关产品推荐

