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

Flutter setState触发重载问题:仅需更新底部琥珀色容器

解决Flutter点击列表项仅更新底部容器不重载FutureBuilder的问题

问题分析

当前代码存在两个核心问题:

  1. FutureBuilder重复执行查询:直接将read()调用写在future参数中,每次setState触发组件重建时,都会重新执行数据库查询,导致列表重新加载。
  2. 全局setState触发全量重建:调用setState会让整个页面的子Widget都重建,包括不需要更新的列表部分。

解决方案

1. 缓存Future避免重复查询

在组件初始化时就执行数据库查询并缓存Future,确保只查询一次:

在State类中添加变量并初始化:

late Future<List?> _productsFuture;

@override
void initState() {
  super.initState();
  // 仅在组件初始化时执行一次查询
  _productsFuture = read(
    "SELECT ProductAdress, ProductName, NeedCount, ScanCount FROM ScanRest WHERE ProductStation = '${widget.nrStatie}' AND BoxID = '${cutieScan}' ORDER BY ProductName ASC;"
  );
}

修改FutureBuilder的future参数:

Expanded(
  child: FutureBuilder<List?>(
    future: _productsFuture, // 使用缓存的Future
    builder: (context, snapshot) {
      // 原有builder逻辑保持不变
      switch (snapshot.connectionState) {
        case ConnectionState.waiting:
          return const Text('Loading....');
        default:
          if (snapshot.hasError) {
            print("call error");
            return Text('Error: ${snapshot.error}');
          } else {
            print("call success = ${snapshot.data}");
            List data = snapshot.data ?? [];
            return ListView.builder(
              itemCount: data.length,
              itemBuilder: (context, index) {
                return Card(
                  elevation: 2,
                  child: GestureDetector(
                    // 后续修改点击逻辑,见步骤2
                    onTap: () {},
                    child: Row(children: [
                      Expanded(
                        flex: 2,
                        child: Text((data[index] as Map)['ProductAdress'].toString()),
                      ),
                      Expanded(
                        flex: 5,
                        child: Text((data[index] as Map)['ProductName'].toString()),
                      ),
                      Expanded(
                        flex: 2,
                        child: Center(child: Text((data[index] as Map)['NeedCount'].toString())),
                      ),
                      Expanded(
                        flex: 2,
                        child: Center(child: Text((data[index] as Map)['ScanCount'].toString())),
                      ),
                    ]),
                  ),
                );
              },
            );
          }
      }
    },
  ),
)

2. 用ValueNotifier局部更新底部容器

使用ValueNotifier存储选中的产品信息,配合ValueListenableBuilder仅更新底部容器,避免全局setState:

在State类中定义ValueNotifier:

final ValueNotifier<Map<String, String>> _selectedProduct = ValueNotifier({
  'test': '',
  'denumProdus': '',
});

修改列表项的点击逻辑:

onTap: () {
  // 更新ValueNotifier的值,而非调用setState
  _selectedProduct.value = {
    'test': (data[index] as Map)['ProductName'].toString(),
    'denumProdus': (data[index] as Map)['ProductSeriesDescr'].toString(),
  };
},

修改底部容器为ValueListenableBuilder包裹:

Visibility(
  visible: !vizibil,
  child: ValueListenableBuilder<Map<String, String>>(
    valueListenable: _selectedProduct,
    builder: (context, selectedValue, child) {
      return Container(
        color: Colors.amber,
        width: double.infinity,
        height: 100,
        child: Center(
          child: Column(
            children: [
              Text(selectedValue['test']!),
              Text(selectedValue['denumProdus']!)
            ],
          ),
        ),
      );
    },
  ),
)

效果说明

修改后:

  • 数据库查询仅在组件初始化时执行一次,后续不会重复触发查询
  • 点击列表项时,仅底部琥珀色容器会更新,列表部分不会重建或重新加载

内容的提问来源于stack exchange,提问作者Dima C

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 06:55:22