Flutter中如何通过传入对象的参数函数修改该对象的属性
解决方案
一、实现点击按钮自动更新文本效果
Flutter采用单向数据流的状态驱动UI设计,你目前的写法中MyButton内部的myString仅在initState阶段初始化一次,后续父组件传入的myText变化不会自动同步,有两种常用实现方案:
方案1:状态提升(官方推荐)
将文本状态放在父组件MyButtonRow中管理,子组件仅负责接收参数展示、触发点击回调,代码修改如下:
class MyButtonRow extends StatefulWidget { const MyButtonRow({Key? key}) : super(key: key); @override _MyButtonRowState createState() => _MyButtonRowState(); } class _MyButtonRowState extends State<MyButtonRow> { // 父组件管理按钮文本状态 late String _currentBtnText; @override void initState() { super.initState(); _currentBtnText = "Hello"; } @override Widget build(BuildContext context) { return Container( width: MediaQuery.of(context).size.width, child: Row( children: <Widget>[ MyButton( onTap: (){ print("Notify me"); // 父组件直接修改状态刷新UI setState(() { _currentBtnText = "更新后的文本"; }); }, myText: _currentBtnText, ), ], ), ); } } // 子组件改为无状态组件,仅接收参数渲染即可 class MyButton extends StatelessWidget { final Function onTap; final String myText; const MyButton({Key? key, required this.onTap, required this.myText}) : super(key: key); @override Widget build(BuildContext context) { return TextButton( onPressed: onTap, child: Text(myText) ); } }
方案2:子组件内部管理状态
如果文本状态不需要父组件感知,可将更新逻辑封装在MyButton内部,点击时先执行内部更新逻辑,再执行父组件传入的回调:
// MyButtonRow代码无需修改,仅修改MyButton部分 class MyButton extends StatefulWidget { final Function onTap; final String initText; const MyButton({Key? key, required this.onTap, required this.initText}) : super(key: key); @override _MyButtonState createState() => _MyButtonState(); } class _MyButtonState extends State<MyButton> { late String myString; @override void initState() { myString = widget.initText; super.initState(); } @override Widget build(BuildContext context) { return TextButton( onPressed: (){ // 先执行内部更新逻辑 setState(() { myString = "更新后的文本"; }); // 再执行父组件传入的回调 widget.onTap.call(); }, child: Text(myString) ); } }
二、父组件MyButtonRow访问MyButton属性的方法
不推荐直接访问子组件内部属性,该做法会导致组件耦合度升高,状态难以维护,优先选择上述状态提升/回调方案。
如果特殊场景必须实现,可以通过GlobalKey获取子组件的State实例进行访问,实现代码如下:
class MyButtonRow extends StatefulWidget { const MyButtonRow({Key? key}) : super(key: key); @override _MyButtonRowState createState() => _MyButtonRowState(); } class _MyButtonRowState extends State<MyButtonRow> { // 定义GlobalKey绑定MyButton的State final GlobalKey<_MyButtonState> _myBtnKey = GlobalKey(); @override Widget build(BuildContext context) { return Container( width: MediaQuery.of(context).size.width, child: Row( children: <Widget>[ MyButton( key: _myBtnKey, // 给子组件绑定key onTap: (){ print("Notify me"); // 通过key访问子组件的属性,修改后手动触发刷新 _myBtnKey.currentState?.setState(() { _myBtnKey.currentState?.myString = "修改后的文本"; }); }, myText: "Hello", ), ], ), ); } } // 注意:如果MyButton和MyButtonRow在不同文件,需要把_MyButtonState的下划线去掉改为公开类 class MyButton extends StatefulWidget { final Function onTap; final String myText; const MyButton({Key? key, required this.onTap, required this.myText}) : super(key: key); @override _MyButtonState createState() => _MyButtonState(); } class _MyButtonState extends State<MyButton> { late Function onTap; late String myString; @override void initState() { onTap = widget.onTap; myString = widget.myText; super.initState(); } @override Widget build(BuildContext context) { return TextButton( onPressed: onTap, child: Text(myString) ); } }
注意:该方式仅适合临时特殊场景使用,生产环境优先使用状态提升方案保证数据流清晰可维护。
内容的提问来源于stack exchange,提问作者Joel
相关产品推荐
相关产品推荐

