外部StatefulWidget类实例更新时如何触发Flutter页面刷新
核心问题
你当前的用法不符合Flutter框架设计规范:
- Widget类的所有属性都需要用
final修饰,属于不可变配置,你直接修改personWidget的可变weight属性本身就是错误用法 - 你把
personWidget实例作为普通数据类存为Homepage的成员变量,Widget是UI配置描述,不是数据载体,不能这么使用 - 即使外层Homepage调用了
setState,你存储的joe实例没有发生变化,所以person组件不会触发重建,也无法感知到weight属性的修改
推荐方案(状态提升,符合Flutter最佳实践)
将体重状态提升到父组件Homepage中维护,person组件仅负责接收参数做展示:
修改person.dart
import 'package:flutter/material.dart'; // Dart类名遵循大驼峰命名规范 class Person extends StatelessWidget { // 所有属性用final修饰,不可变 final int weight; const Person({Key? key, required this.weight}) : super(key: key); @override Widget build(BuildContext context) { return Center( child: Text( weight.toString(), style: const TextStyle(fontSize: 24), ), ); } }
修改homepage.dart
import 'package:mvs/person.dart'; import 'package:flutter/material.dart'; class Homepage extends StatefulWidget { const Homepage({Key? key}) : super(key: key); @override _HomepageState createState() => _HomepageState(); } class _HomepageState extends State<Homepage> { // 体重状态在父组件维护,不存储Person组件实例 int _joeWeight = 23; final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); @override Widget build(BuildContext context) { return Material( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 每次build时创建新的Person实例,传入最新的weight参数 Person(weight: _joeWeight), OutlinedButton( onPressed: () { showModalBottomSheet( context: context, builder: (context) { return Form( key: _formKey, child: Column( children: [ Padding( padding: const EdgeInsets.all(12.0), child: TextFormField( onSaved: (String? value) { if (value != null && int.parse(value) > 0) { setState(() { // 更新父组件的体重状态,触发重建后Person组件自动更新 _joeWeight = int.parse(value); }); } }, keyboardType: TextInputType.number, maxLength: 3, initialValue: _joeWeight.toString(), decoration: const InputDecoration( icon: Icon(Icons.label), ), validator: (value) { if (value == null || value.isEmpty) { return "请输入数值"; } return null; }, ), ), OutlinedButton( onPressed: () { if(_formKey.currentState!.validate()) { _formKey.currentState!.save(); Navigator.pop(context); } }, child: const Text("提交"), ) ], ), ); }, ); }, child: const Text("更新体重"), ) ], ), ); } }
可选方案(触发Person组件内部setState,不推荐)
如果确实需要在Person组件内部维护状态,可以通过GlobalKey获取Person组件的state实例,调用内部更新方法:
修改person.dart
import 'package:flutter/material.dart'; class Person extends StatefulWidget { final int initWeight; const Person({Key? key, required this.initWeight}) : super(key: key); @override _PersonState createState() => _PersonState(); } class _PersonState extends State<Person> { late int weight; @override void initState() { super.initState(); weight = widget.initWeight; } // 暴露更新方法,内部调用setState触发刷新 void updateWeight(int newWeight) { setState(() { weight = newWeight; }); } @override Widget build(BuildContext context) { return Center( child: Text( weight.toString(), style: const TextStyle(fontSize: 24), ), ); } }
修改homepage.dart
import 'package:mvs/person.dart'; import 'package:flutter/material.dart'; class Homepage extends StatefulWidget { const Homepage({Key? key}) : super(key: key); @override _HomepageState createState() => _HomepageState(); } class _HomepageState extends State<Homepage> { // 定义GlobalKey关联Person组件的state final GlobalKey<_PersonState> _personKey = GlobalKey<_PersonState>(); final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); @override Widget build(BuildContext context) { return Material( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 给Person组件传入key Person(key: _personKey, initWeight: 23), OutlinedButton( onPressed: () { showModalBottomSheet( context: context, builder: (context) { return Form( key: _formKey, child: Column( children: [ Padding( padding: const EdgeInsets.all(12.0), child: TextFormField( onSaved: (String? value) { if (value != null && int.parse(value) > 0) { // 通过key拿到state实例调用更新方法 _personKey.currentState?.updateWeight(int.parse(value)); } }, keyboardType: TextInputType.number, maxLength: 3, initialValue: _personKey.currentState?.weight.toString() ?? '23', decoration: const InputDecoration( icon: Icon(Icons.label), ), validator: (value) { if (value == null || value.isEmpty) { return "请输入数值"; } return null; }, ), ), OutlinedButton( onPressed: () { if(_formKey.currentState!.validate()) { _formKey.currentState!.save(); Navigator.pop(context); } }, child: const Text("提交"), ) ], ), ); }, ); }, child: const Text("更新体重"), ) ], ), ); } }
内容的提问来源于stack exchange,提问作者Sachu
相关产品推荐
相关产品推荐

