Flutter中两个Stateful类共用方法时如何正确调用setState?
方案1:回调参数方案(改造成本最低)
给公共注册方法增加状态回调参数,将组件内的setState逻辑通过回调传入公共方法:
Future<void> signupToFirebase({ VoidCallback? onLoadingStart, VoidCallback? onLoadingEnd, Function(String error)? onError, }) async { onLoadingStart?.call(); try { // 原有Firebase注册逻辑 // await Firebase.instance.signupWithEmailAndPassword... } catch (e) { onError?.call(e.toString()); } finally { onLoadingEnd?.call(); } }
在两个组件内定义加载状态,调用公共方法时传入对应setState回调即可:
class _SingupLargeState extends State<SignupLarge> { bool _isLoading = false; @override Widget build(BuildContext context) { return Column( children: [ // 其他组件 if(_isLoading) const CircularProgressIndicator(), ElevatedButton( onPressed: _isLoading ? null : _handleSignup, child: const Text('Click me') ) ], ); } void _handleSignup() { signupToFirebase( onLoadingStart: () => setState(() => _isLoading = true), onLoadingEnd: () => setState(() => _isLoading = false), onError: (error) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(error))); } ); } } // SignupSmall组件的改法和上述完全一致,核心注册逻辑无需重复编写
方案2:Mixin封装(无重复代码,维护性最优)
通过Dart的Mixin能力将注册逻辑、加载状态、错误处理完全封装,两个组件直接复用即可:
mixin SignupMixin<T extends StatefulWidget> on State<T> { bool _isLoading = false; bool get isLoading => _isLoading; Future<void> handleSignup() async { setState(() => _isLoading = true); try { // 原有Firebase注册逻辑 // await Firebase.instance.signupWithEmailAndPassword... // 注册成功后的跳转等通用逻辑也可以统一写在这里 } catch (e) { if(mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(e.toString()))); } } finally { if(mounted) { setState(() => _isLoading = false); } } } }
两个组件的State直接引入Mixin即可,无需重复编写任何逻辑:
class _SingupLargeState extends State<SignupLarge> with SignupMixin { @override Widget build(BuildContext context) { return Column( children: [ // 其他组件 if(isLoading) const CircularProgressIndicator(), ElevatedButton( onPressed: isLoading ? null : handleSignup, child: const Text('Click me') ) ], ); } } class _SignupSmallState extends State<SignupSmall> with SignupMixin { @override Widget build(BuildContext context) { return ListView( children: [ // 其他组件 if(isLoading) const CircularProgressIndicator(), ElevatedButton( onPressed: isLoading ? null : handleSignup, child: const Text('Click me') ) ], ); } }
该方案所有注册相关逻辑仅需维护Mixin一处,后续迭代修改不会出现多端同步问题。
可选方案:状态上提
如果后续有更多组件需要共享注册状态,可以将父组件MyPageExample改为Stateful,统一管理加载状态和注册逻辑,再通过参数传递给两个子组件即可。
内容的提问来源于stack exchange,提问作者Fernando Delgadillo
相关产品推荐
相关产品推荐

