Flutter中如何从StatefulWidget访问其对应State类中的状态字段?
Flutter 中StatefulWidget访问State内部字段的解决方案
Flutter的设计规范中,StatefulWidget的组件类本身仅负责存储静态配置信息,和生命周期绑定的可变状态归State类管理,所以将依赖可变状态的trainingToString方法放在Widget类中本身不符合设计逻辑,优先调整代码结构,以下是几种可行的实现方案:
方案1:调整逻辑位置(最推荐)
直接把trainingToString方法移到_TrainingState类中,本身该方法依赖State里的可变状态,放在State里是最合理的实现:
class Training extends StatefulWidget { const Training({Key? key}) : super(key: key); @override State<Training> createState() => _TrainingState(); } class _TrainingState extends State<Training> { int peopleSelected = 0; void updatePeopleSelected(int peopleSelected){ setState((){ this.peopleSelected = peopleSelected; }); } // 状态相关方法移到State内部 String trainingToString(){ return 'people selected: $peopleSelected'; } @override Widget build(BuildContext context) { return Container(); } }
如果外部需要调用这个方法或者获取状态值,可以配合回调或者状态管理向外暴露。
方案2:状态提升(适合父组件需要用到该状态的场景)
把peopleSelected状态放到父组件HomeScreen中管理,Training组件通过构造函数接收值,并且通过回调通知父组件修改状态,符合Flutter单向数据流的设计:
// 父组件 class HomeScreen extends StatefulWidget { const HomeScreen({Key? key}) : super(key: key); @override State<HomeScreen> createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> { int _peopleSelected = 0; String trainingToString() { return 'people selected: $_peopleSelected'; } @override Widget build(BuildContext context) { return Training( peopleSelected: _peopleSelected, onUpdate: (val) => setState(() => _peopleSelected = val), ); } } // 子组件 class Training extends StatefulWidget { const Training({ Key? key, required this.peopleSelected, required this.onUpdate, }) : super(key: key); final int peopleSelected; final Function(int) onUpdate; // 直接拿组件配置的静态字段即可 String trainingToString(){ return 'people selected: $peopleSelected'; } @override State<Training> createState() => _TrainingState(); } class _TrainingState extends State<Training> { @override Widget build(BuildContext context) { // 更新值的时候调用widget.onUpdate(新值)即可触发父组件更新 return Container(); } }
该方案后续维护成本最低,是官方推荐的状态管理方式。
方案3:通过GlobalKey获取State实例(不推荐,仅特殊场景使用)
如果一定要保持现有结构,可以用GlobalKey来关联Training组件和对应的State实例,注意要把State类的下划线去掉改成公开的,否则外部无法访问:
// 先创建全局key final trainingKey = GlobalKey<TrainingState>(); // 父组件使用时传入key class _HomeScreenState extends State<HomeScreen> { @override Widget build(BuildContext context) { return Training(key: trainingKey); } // 需要调用时直接拿key的currentState void someMethod() { final state = trainingKey.currentState; if (state != null) { print('people selected: ${state.peopleSelected}'); } } } // Training组件的State改成公开的,去掉下划线 class Training extends StatefulWidget { const Training({Key? key}) : super(key: key); @override State<Training> createState() => TrainingState(); } class TrainingState extends State<Training> { // 公开字段 int peopleSelected = 0; void updatePeopleSelected(int peopleSelected){ setState((){ this.peopleSelected = peopleSelected; }); } @override Widget build(BuildContext context) { return Container(); } }
注意:GlobalKey开销较大,非必要不要使用,同时不要大量全局存储GlobalKey,容易造成内存泄漏。
内容的提问来源于stack exchange,提问作者lucasfelber
相关产品推荐
相关产品推荐

