如何用Provider实现子组件操作后更新父级好友列表页面?
使用Provider实现子组件通知父组件刷新好友列表
核心思路是通过Provider的ChangeNotifier维护好友列表状态,子组件完成删除/拉黑操作后触发状态更新,父组件监听状态变化自动刷新列表,完全符合组件职责划分的直觉。
1. 创建好友状态管理类
新建一个继承ChangeNotifier的类,统一处理好友数据的加载、删除、拉黑逻辑,操作完成后调用notifyListeners()通知所有监听组件刷新。
import 'package:flutter/foundation.dart'; import '../services/database.dart'; class FriendListProvider extends ChangeNotifier { final Database _database = Database(); List<Map<String, dynamic>> _friends = []; // 对外暴露只读的好友列表 List<Map<String, dynamic>> get friends => _friends; // 从Firestore加载最新好友列表 Future<void> loadFriends() async { _friends = await _database.getFriends(); // 假设你的Database类有该方法 notifyListeners(); } // 删除好友并刷新列表 Future<void> removeFriend(String friendUID) async { await _database.removeFriend(friendUID); await loadFriends(); notifyListeners(); } // 拉黑好友并刷新列表 Future<void> blockFriend(String friendUID) async { await _database.blockFriend(friendUID); await loadFriends(); notifyListeners(); } }
2. 父组件集成Provider
在好友列表页面用ChangeNotifierProvider包裹,通过Consumer监听状态变化,自动重建好友列表。
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import './friendRow.dart'; import './friend_list_provider.dart'; class FriendListPage extends StatefulWidget { const FriendListPage({Key? key}) : super(key: key); @override State<FriendListPage> createState() => _FriendListPageState(); } class _FriendListPageState extends State<FriendListPage> { @override void initState() { super.initState(); // 页面初始化时加载好友列表 WidgetsBinding.instance.addPostFrameCallback((_) { Provider.of<FriendListProvider>(context, listen: false).loadFriends(); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('好友列表')), body: Consumer<FriendListProvider>( builder: (context, provider, child) { if (provider.friends.isEmpty) { return const Center(child: Text('暂无好友')); } return ListView.builder( itemCount: provider.friends.length, itemBuilder: (context, index) { final friend = provider.friends[index]; return FriendRow( friendUsername: friend['username'], friendUID: friend['uid'], ); }, ); }, ), ); } }
3. 修改FriendRow子组件
移除子组件内的数据库实例,改为通过Provider获取状态管理类,调用对应的操作方法,操作完成后自动触发父组件刷新。
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import './friend_list_provider.dart'; enum MoreOptions { RemoveFriend, Block } class FriendRow extends StatelessWidget { const FriendRow({ Key? key, required this.friendUsername, required this.friendUID, }) : super(key: key); final String friendUsername; final String friendUID; Future _moreOptionsDialog(BuildContext context, MoreOptions selectedItem) { String dialogTitle = ''; if (selectedItem == MoreOptions.RemoveFriend) { dialogTitle = '删除好友'; } if (selectedItem == MoreOptions.Block) { dialogTitle = '拉黑好友'; } final provider = Provider.of<FriendListProvider>(context, listen: false); return showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text(dialogTitle), actions: [ TextButton( onPressed: () async { if (selectedItem == MoreOptions.RemoveFriend) { await provider.removeFriend(friendUID); } if (selectedItem == MoreOptions.Block) { await provider.blockFriend(friendUID); } Navigator.of(context).pop(); }, child: const Text('确认'), ), TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('取消'), ), ], ); }, ); } @override Widget build(BuildContext context) { return Row( children: [ Expanded( flex: 2, child: Image.asset('assets/images/userPicture.png'), ), Expanded( flex: 8, child: Text(friendUsername), ), Expanded( flex: 1, child: PopupMenuButton<MoreOptions>( onSelected: (MoreOptions selectedItem) { _moreOptionsDialog(context, selectedItem); }, itemBuilder: (BuildContext context) => <PopupMenuEntry<MoreOptions>>[ const PopupMenuItem<MoreOptions>( value: MoreOptions.RemoveFriend, child: Text('删除好友'), ), const PopupMenuItem<MoreOptions>( value: MoreOptions.Block, child: Text('拉黑好友'), ), ], ), ), ], ); } }
关键说明
- 状态管理类统一处理数据逻辑,子组件仅负责UI渲染和触发操作,符合单一职责原则。
notifyListeners()会通知所有Consumer监听的组件重建,父组件的ListView自动加载最新好友列表。- 子组件中使用
Provider.of<T>(context, listen: false)是因为仅需获取实例调用方法,无需监听状态变化。
内容的提问来源于stack exchange,提问作者whatwhatwhat
相关产品推荐
相关产品推荐

