Flutter状态刷新问题:如何通过onTap从其他脚本更新Widget?
我是Flutter新手,目前遇到以下问题:如何通过onTap方法从其他脚本更新Widget?我尝试使用setState()但持续报错。当前我使用FutureBuilder和GridView.builder获取数据表中的所有记录,希望能按分类ID更新数据,恳请提供帮助。
class ItemsWidget extends StatefulWidget { @override ItemsPage createState() => ItemsPage(); } class ItemsPage extends State<ItemsWidget> { static var catId = 0; late Future<List<Item>> items; Future<List<Item>> fetchItems(int category) async { final response = await http.get(Uri.parse('http://10.0.2.2:8000/api/v1/productList/')); if (response.statusCode == 200) { List<dynamic> list = json.decode(response.body); var it = list.map((item) => Item.fromJson(item)).toList(); if (category == 0){ List<Item> items = list.map((item) => Item.fromJson(item)).toList(); return items; }else{ List<Item> items = it.where((item) => item.category == category).toList(); return items; } } else { throw Exception('Error'); } } @override void initState() { print(catId); items = fetchItems(catId); print("fetch"); super.initState(); } static String utf8convert(String text) { List<int> bytes = text.toString().codeUnits; return utf8.decode(bytes); } @override Widget build(BuildContext context) { return FutureBuilder<List<Item>>( future: items, builder: (BuildContext context, AsyncSnapshot<List<Item>> snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center( child: CircularProgressIndicator( color: Colors.deepPurpleAccent, ), ); } if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasError) { return Center( child: Text( 'An ${snapshot.error} occurred', style: const TextStyle(fontSize: 18, color: Colors.red), ), ); } else if (snapshot.hasData) { return GridView.builder( ... ); } ; }; return const Center( child: CircularProgressIndicator(), ); }); }
解决方案
你的代码核心问题
- 使用
static修饰catId:静态变量属于类而非State实例,修改它不会触发setState()的组件重建 - 仅在
initState()中获取一次数据:组件初始化时加载数据,但没有逻辑在分类ID变化时重新请求数据
修改后的完整代码
class ItemsWidget extends StatefulWidget { // 可选:从父组件传递初始分类ID final int initialCatId; const ItemsWidget({Key? key, this.initialCatId = 0}) : super(key: key); @override ItemsPage createState() => ItemsPage(); } class ItemsPage extends State<ItemsWidget> { int catId = 0; // 移除static修饰符 late Future<List<Item>> items; Future<List<Item>> fetchItems(int category) async { final response = await http.get(Uri.parse('http://10.0.2.2:8000/api/v1/productList/')); if (response.statusCode == 200) { List<dynamic> list = json.decode(response.body); final allItems = list.map((item) => Item.fromJson(item)).toList(); // 简化分类过滤逻辑 return category == 0 ? allItems : allItems.where((item) => item.category == category).toList(); } else { throw Exception('加载商品失败'); } } // 新增刷新数据的方法 void _refreshItems(int newCatId) { setState(() { catId = newCatId; items = fetchItems(catId); // 根据新分类ID重新请求数据 }); } @override void initState() { catId = widget.initialCatId; items = fetchItems(catId); super.initState(); } static String utf8convert(String text) { List<int> bytes = text.toString().codeUnits; return utf8.decode(bytes); } @override Widget build(BuildContext context) { return Column( children: [ // 示例:分类按钮,点击触发刷新 Row( mainAxisAlignment: MainAxisAlignment.center, children: [ TextButton( onPressed: () => _refreshItems(0), child: const Text('全部商品'), ), const SizedBox(width: 16), TextButton( onPressed: () => _refreshItems(1), child: const Text('分类1'), ), const SizedBox(width: 16), TextButton( onPressed: () => _refreshItems(2), child: const Text('分类2'), ), ], ), Expanded( child: FutureBuilder<List<Item>>( future: items, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center( child: CircularProgressIndicator(color: Colors.deepPurpleAccent), ); } if (snapshot.hasError) { return Center( child: Text( '错误:${snapshot.error}', style: const TextStyle(fontSize: 18, color: Colors.red), ), ); } if (snapshot.hasData) { return GridView.builder( padding: const EdgeInsets.all(8), itemCount: snapshot.data!.length, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 8, mainAxisSpacing: 8, ), itemBuilder: (context, index) { final item = snapshot.data![index]; return Card( child: Center( child: Text(utf8convert(item.name)), // 替换为你的Item模型字段 ), ); }, ); } return const Center(child: CircularProgressIndicator()); }, ), ), ], ); } }
从其他组件触发更新
如果需要从外部组件(比如父组件或兄弟组件)触发分类切换,可以用以下两种方式:
回调函数 + GlobalKey
给ItemsWidget添加回调参数,再用GlobalKey获取State实例调用刷新方法:// 父组件中定义GlobalKey final itemsKey = GlobalKey<ItemsPageState>(); // 父组件的build方法中使用ItemsWidget ItemsWidget( key: itemsKey, initialCatId: 0, ) // 在外部组件的onTap中调用 itemsKey.currentState?._refreshItems(3); // 切换到分类3状态管理工具
复杂场景下可以用Provider、Riverpod或Bloc等状态管理工具,实现跨组件的状态共享和自动更新。
内容的提问来源于stack exchange,提问作者Johny Razor
相关产品推荐
相关产品推荐

