You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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());
            },
          ),
        ),
      ],
    );
  }
}

从其他组件触发更新

如果需要从外部组件(比如父组件或兄弟组件)触发分类切换,可以用以下两种方式:

  1. 回调函数 + GlobalKey
    给ItemsWidget添加回调参数,再用GlobalKey获取State实例调用刷新方法:

    // 父组件中定义GlobalKey
    final itemsKey = GlobalKey<ItemsPageState>();
    
    // 父组件的build方法中使用ItemsWidget
    ItemsWidget(
      key: itemsKey,
      initialCatId: 0,
    )
    
    // 在外部组件的onTap中调用
    itemsKey.currentState?._refreshItems(3); // 切换到分类3
    
  2. 状态管理工具
    复杂场景下可以用Provider、Riverpod或Bloc等状态管理工具,实现跨组件的状态共享和自动更新。


内容的提问来源于stack exchange,提问作者Johny Razor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 06:57:33