如何在Flutter中不使用GetX/Provider,通过父StatefulWidget更新子组件值
解决方案:不使用状态管理库实现父组件更新子组件TextFormField
在Flutter中,不依赖GetX、Provider等状态管理库时,可通过GlobalKey直接获取子组件的State实例,调用其内部方法更新TextFormField的值,具体实现步骤如下:
1. 修改子组件,暴露更新方法
调整子组件的State类为公共可见(去掉类名前的下划线),并添加用于更新工资输入框的公共方法:
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:site_management/supervisors/supervisor_services/supervisor_attendance_services.dart'; class LabourAttendanceWidget extends StatefulWidget { const LabourAttendanceWidget({ Key? key, required this.name, required this.wages, required this.isPrensent, required this.workerId, required this.masterAttendanceId, }) : super(key: key); final int workerId; final int masterAttendanceId; final String name; final String wages; final String isPrensent; @override LabourAttendanceWidgetState createState() => LabourAttendanceWidgetState(); } // 去掉下划线,让State类可被父组件通过GlobalKey访问 class LabourAttendanceWidgetState extends State<LabourAttendanceWidget> { final TextEditingController _wagesController = TextEditingController(); String _character = ""; Timer? searchOnStoppedTyping; _onChangeHandler(value) { const duration = Duration(milliseconds: 800); if (searchOnStoppedTyping != null) { setState(() => searchOnStoppedTyping?.cancel()); } setState(() => searchOnStoppedTyping = Timer(duration, () => submitWages(value))); } submitWages(value) { SupervisorAttendanceServices.storeWorkerWages( widget.workerId, value, widget.masterAttendanceId); } // 公共方法:供父组件调用更新输入框值 void updateWages(String newWages) { setState(() { _wagesController.text = newWages; _onChangeHandler(newWages); // 需要自动触发提交逻辑则保留,否则可移除 }); } @override void initState() { super.initState(); _character = widget.isPrensent; _wagesController.text = widget.wages; } @override Widget build(BuildContext context) { return Card( child: Column(children: [ Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [ const SizedBox(width: 10, height: 50), const Icon(FeatherIcons.user), const SizedBox(width: 20), Text(widget.name, style: const TextStyle(fontSize: 18)), ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ SizedBox( width: 150, height: 60, child: TextFormField( controller: _wagesController, onChanged: _onChangeHandler, decoration: const InputDecoration( hintText: "Wages", prefixIcon: Icon(Icons.wallet, color: Colors.blue)), )), Row( children: [ Radio( value: "P", groupValue: _character, fillColor: MaterialStateColor.resolveWith((states) => Colors.green), onChanged: (selectedValue) { setState(() { _character = selectedValue.toString(); SupervisorAttendanceServices.changeAttendance( widget.workerId, _character, widget.masterAttendanceId) .then((response) { if (response != 1) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( behavior: SnackBarBehavior.floating, content: Row( children: const [ Icon(FeatherIcons.home), SizedBox(width: 10), Text("Something went wrong !"), ], ), ), ); } }); }); }, ), const Text("P"), Radio( value: "A", fillColor: MaterialStateColor.resolveWith((states) => Colors.red), groupValue: _character, onChanged: (selectedValue) { setState(() { _wagesController.text = "0"; _onChangeHandler("0"); _character = selectedValue.toString(); SupervisorAttendanceServices.changeAttendance( widget.workerId, _character, widget.masterAttendanceId); }); }), const Text("A"), ], ) ], ) ]), ); } }
2. 修改父组件,使用GlobalKey管理子组件
在父组件中创建GlobalKey列表绑定每个子组件,并添加触发更新的按钮:
// 父组件的State类中添加成员变量 List<GlobalKey<LabourAttendanceWidgetState>> _childKeys = []; // 修改FutureBuilder部分 FutureBuilder( future: SupervisorAttendanceServices.getAttendancesDetailsList(widget.attendanceId), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasData) { var data = snapshot.data['labour']; // 初始化子组件的GlobalKey列表 _childKeys = List.generate(data.length, (index) => GlobalKey<LabourAttendanceWidgetState>()); return Column( children: [ // 添加触发更新的按钮 ElevatedButton( onPressed: () { // 示例1:更新所有子组件的工资为"100" for (var key in _childKeys) { key.currentState?.updateWages("100"); } // 示例2:更新特定worker的工资(根据workerId定位) // int targetWorkerId = 123; // 替换为目标workerId // int targetIndex = data.indexWhere((item) => item['worker_id'] == targetWorkerId); // if (targetIndex != -1) { // _childKeys[targetIndex].currentState?.updateWages("150"); // } }, child: const Text("更新子组件工资"), ), Expanded( child: ListView.builder( itemCount: data.length, physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemBuilder: (BuildContext context, int index) { return LabourAttendanceWidget( key: _childKeys[index], // 绑定GlobalKey workerId: data[index]['worker_id'], masterAttendanceId: widget.attendanceId, name: data[index]['worker_name'], wages: data[index]['attendance_worker_wages'], isPrensent: data[index]['attendance_worker_presense'].toString(), ); }), ), ], ); } else if (snapshot.hasError) { return const Center(child: Text("Something went wrong !")); } else { return const Center(child: LinearProgressIndicator()); } }, ),
核心原理说明
- GlobalKey:跨Widget层级获取子组件的State实例,直接调用其内部公共方法。
- 子组件暴露
updateWages方法:父组件可直接控制TextFormField内容,同时保留原有输入提交逻辑。 - 移除GetX依赖:删除原GetX控制器相关代码,避免依赖第三方状态管理库。
内容的提问来源于stack exchange,提问作者swapnil mane
相关产品推荐
相关产品推荐

