如何为Flutter无状态组件传入自定义按钮及回调函数?
实现方案
要让FileUploadMutation组件支持传入任意类型按钮并复用,核心是通过**按钮构建器(Button Builder)**将按钮的创建逻辑交给外部调用方,同时把文件上传的核心逻辑封装在组件内部供外部按钮触发。
步骤1:修改组件定义
更新FileUploadMutation,添加一个buttonBuilder参数——这是一个函数,接收封装好的上传方法和Mutation的状态结果,返回任意类型的按钮组件。同时在组件内部封装上传逻辑,避免外部关注runMutation的细节。
修改后的完整代码:
class FileUploadMutation extends StatelessWidget { const FileUploadMutation({ required this.user, required this.switchScreenFn, this.buttonBuilder, super.key, }); final User user; final Function switchScreenFn; // 按钮构建器:接收上传方法和Mutation状态,返回自定义按钮 final Widget Function(Future<void> Function() upload, QueryResult result)? buttonBuilder; @override Widget build(BuildContext context) { return Mutation( options: MutationOptions( document: gql(fileUploadMutation), ), builder: (runMutation, result) { // 封装上传核心逻辑,供外部按钮调用 Future<void> _upload() async { List<MultipartFile> files = user.files; await runMutation({ 'containerName': containerName, 'files': files, }); switchScreenFn(); } // 优先使用外部传入的按钮构建器,无传入则使用默认ElevatedButton return buttonBuilder?.call(_upload, result) ?? ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.red, elevation: 0, ), onPressed: result.isLoading ? null : _upload, child: result.isLoading ? const CircularProgressIndicator(color: Colors.white) : const Text("Continue"), ); }, ); } }
步骤2:调用组件时传入不同按钮
现在可以在任意位置调用FileUploadMutation,按需传入不同类型的按钮:
示例1:传入OutlineButton
FileUploadMutation( user: currentUser, switchScreenFn: () => Navigator.pushNamed(context, '/next-screen'), buttonBuilder: (upload, result) { return OutlineButton( borderSide: const BorderSide(color: Colors.blue), onPressed: result.isLoading ? null : upload, child: result.isLoading ? const SizedBox(width:20, height:20, child: CircularProgressIndicator()) : const Text("上传文件"), ); }, )
示例2:传入IconButton
FileUploadMutation( user: currentUser, switchScreenFn: () => setState(() => isUploaded = true), buttonBuilder: (upload, result) { return IconButton( icon: result.isLoading ? const CircularProgressIndicator(size:20) : const Icon(Icons.cloud_upload), onPressed: result.isLoading ? null : upload, color: Colors.green, ); }, )
示例3:自定义样式的ElevatedButton
FileUploadMutation( user: currentUser, switchScreenFn: () {}, buttonBuilder: (upload, result) { return ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.purple, padding: const EdgeInsets.symmetric(horizontal:30, vertical:12), ), onPressed: result.isLoading ? null : upload, child: result.isLoading ? const Text("上传中...") : const Text("开始上传", style: TextStyle(fontSize:16)), ); }, )
核心优势
- 高度灵活:支持任意按钮类型,样式、内容完全由调用方控制
- 逻辑封装:文件上传和
Mutation逻辑都在组件内部,外部只需调用upload方法即可 - 状态同步:自动同步
Mutation的加载状态,方便处理按钮禁用、加载提示等逻辑
内容的提问来源于stack exchange,提问作者Sumchans
相关产品推荐
相关产品推荐

