Flutter/Dart如何访问State内变量,获取子Widget状态值更新父组件数据?
实现方案
完全可以实现,Flutter官方优先推荐单向数据流的状态提升方案,特殊场景也可以通过GlobalKey直接访问子State,两种方案的具体实现如下:
方案1:状态提升(推荐)
把所有时长数据存放在父Widget的State中,子组件只负责渲染和交互,不持有私有状态,完全避免跨组件访问状态的问题:
- 给自定义时间选择器Widget新增
onDurationChanged回调参数,每次用户在子组件中修改起止时间时,就通过这个回调将最新时长传递给父组件 - 父组件用一个
List<Duration>存储所有时间选择器对应的时长,总时长直接通过该列表求和得到 - 触发
Dismissible的删除回调时,直接取出对应下标的时长从总时长中扣减即可
代码示例:
// 父Widget State代码 class _MyHomePageState extends State<MyHomePage> { List<Duration> allDuration = []; Duration total = Duration.zero; // 重新计算总时长 void updateTotal() { total = allDuration.fold(Duration.zero, (prev, curr) => prev + curr); setState(() {}); } @override Widget build(BuildContext context) { return ListView.builder( itemCount: allDuration.length, itemBuilder: (context, index) => Dismissible( key: UniqueKey(), onDismissed: (dir) { // 直接获取要删除的时长扣减 final removed = allDuration.removeAt(index); total -= removed; setState(() {}); }, child: TimePicker( initDuration: allDuration[index], onChanged: (newDuration) { allDuration[index] = newDuration; updateTotal(); }, ), ), ); } }
方案2:GlobalKey访问子State(不推荐)
如果子组件逻辑非常复杂,无法做状态提升,可以通过GlobalKey直接获取子State实例拿到数据:
- 先给子State类增加公开的get方法暴露需要的时长值,不要直接访问私有变量
- 父组件维护一个GlobalKey列表,和列表项一一对应
- 删除时通过对应GlobalKey获取子State的时长值进行扣减
代码示例:
// 子Widget代码 class TimePicker extends StatefulWidget { const TimePicker({super.key}); @override State<TimePicker> createState() => _TimePickerState(); } class _TimePickerState extends State<TimePicker> { Duration _duration = Duration.zero; // 公开get方法暴露时长 Duration get currentDuration => _duration; } // 父Widget State代码 class _MyHomePageState extends State<MyHomePage> { List<GlobalKey<_TimePickerState>> keys = []; Duration total = Duration.zero; @override Widget build(BuildContext context) { return ListView.builder( itemCount: keys.length, itemBuilder: (context, index) { if(keys.length <= index) keys.add(GlobalKey<_TimePickerState>()); return Dismissible( key: UniqueKey(), onDismissed: (dir) { final removedDuration = keys[index].currentState?.currentDuration ?? Duration.zero; total -= removedDuration; keys.removeAt(index); setState(() {}); }, child: TimePicker(key: keys[index]), ); }, ); } }
注意:该方案耦合度高,动态列表场景容易出现key匹配错误的问题,没有特殊需求请优先使用状态提升方案。
内容的提问来源于stack exchange,提问作者codebyjakob
相关产品推荐
相关产品推荐

