Flutter 局部刷新小组件汇总

前言:
在Flutter实际的开发工作中,局部刷新也就是更小的颗粒度刷新一直是开发者追求的一个目标,总结一下几个常用的局部刷新的小组件。
首先来说有很多状态管理的框架,可以轻松实现局部刷新。
  1. Provider :使用 Consumer 或者 Selector 来实现。

  2. Bloc :使用 BuildWhen 来实现。

  3. GetX :使用 Obx() 来实现。

  4. RiverPod通过 ref.watch(homeDetailScrollRiverProvider.select 或者 细化拆分river 来实现。

其实,Flutter本身自己也提供了局部刷新的小组件,随着业务的复杂,用这些小组件配合状态管理框架一起来使用,会使颗粒度更细,法力无边。
一. StatefulWidget

在写页面时,尽量的细化和封装组件,小组件继承 StatefulWidget 通过 setStates 来更新小组件自己,页面上其他组件不变。

二. StatefulBuilder

有些时候可能一个小组件或者页面相对复杂,而需要根据状态变化的 Widget 只有一个,要想做到更小颗粒度的刷新那肯定就不能调用 setStates ,因为小组件本身不需要全部重新 build 只是需要重新构建根据状态变化的 Widget 即可。

简单来说,StatefulBuilder 是一个 "便携式"、"嵌入式"的 StatefulWidget , 它的独特之处在于它的 builder 方法,这个方法提供了一个 setState 回调,你可以用这个回调来触发仅重建 StatefulBuilder 内部 UI 的局部刷新。

在实际的项目开发过程中有很多使用的场景,比如 表单选择 点赞 收藏 等 。

写了一个例子,点击 widget 改变自身文字显示 代码如下:

dart 复制代码
return StatefulBuilder(
  builder: (context, buildSetState) {
    return InkWell(
      onTap: () {
        _title = Until.getTitle();
        buildSetState.call(() {});
      },
      child: Container(
        width: double.infinity,
        color: Colors.white,
        alignment: Alignment.center,
        padding: EdgeInsets.symmetric(vertical: 12.h, horizontal: 18.w),
        child: Text(_title),
      ),
    );
  },
);
三. ValueNotifier + ValueListenableBuilder

ValueListenableBuilder 的使用场景和 StatefulBuilder 类似,二者在很多的场景中可以互相替代。

ValueListenableBuilder官方推荐 的用于中等复杂度场景的局部刷新方案。它将数据(ValueNotifier)UI(ValueListenableBuilder) 分离,实现完美解耦。

极致的局部刷新ValueListenableBuilderbuilder 方法就是需要刷新的最小范围。

完美解耦 :组件之间不需要互相知道对方的存在,它们只通过 ValueNotifier通信。

写了一个例子,点击 widget 改变自身文字显示 代码如下:

dart 复制代码
Widget _valueNotifierWidget() {
  return ValueListenableBuilder<String>(
    valueListenable: _valueNotifier,
    builder: (context, value, child) {
      return InkWell(
        onTap: () {
          _valueNotifier.value = Until.getTitle();
        },
        child: Container(
          width: double.infinity,
          color: Colors.white,
          alignment: Alignment.center,
          margin: EdgeInsets.symmetric(vertical: 12.h),
          padding: EdgeInsets.symmetric(vertical: 12.h, horizontal: 18.w),
          child: Text(value),
        ),
      );
    },
  );
}
三. StreamBuilder

对于异步数据流(比如来自网络、文件读取),用 StreamBuilder 来实现局部刷新也有助于解耦。

写了一个例子,网络请求数据,成功之后更新自身文字展示 代码如下:

dart 复制代码
Widget _streamBuilderWidget() {
  return StreamBuilder<CarModel?>(
    stream: _carStream,
    builder: (context, snapshot) {
      if (snapshot.hasError) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.error_outline, color: Colors.red, size: 60),
            const SizedBox(height: 16),
            Text(
              '出错啦: ${snapshot.error}',
              style: Theme.of(context).textTheme.bodyLarge,
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 16),
            FilledButton(
              onPressed: _refreshData, // 出错后可以重试
              child: const Text('重试'),
            ),
          ],
        );
      } else if (snapshot.hasData) {
        return Container(
          color: Colors.blue,
          padding: const EdgeInsets.all(8.0),
          child: Text(snapshot.data?.description ?? ""),
        );
      } else {
        return const CircularProgressIndicator();
      }
    },
  );
}
四. FutureBuilder

FutureBuilder 是 Flutter 中用于处理单次异步操作 并据此构建 UI 的强大组件。它比 StreamBuilder 更简单,适用于绝大多数"请求-响应"模式的场景,如网络请求、数据库查询、本地文件读取等。

写了一个例子,网络请求数据,成功之后更新自身文字展示 代码如下:

dart 复制代码
Widget _futureBuilderWidget() {
  return FutureBuilder<CarModel?>(
    future: _futureCar,
    builder: (context, snapshot) {
      if (snapshot.hasError) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.error_outline, color: Colors.red, size: 60),
            const SizedBox(height: 16),
            Text(
              '出错啦: ${snapshot.error}',
              style: Theme.of(context).textTheme.bodyLarge,
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 16),
            FilledButton(
              onPressed: _refreshStream, // 出错后可以重试
              child: const Text('重试'),
            ),
          ],
        );
      }
      if (snapshot.hasData) {
        final CarModel? carModel = snapshot.data;
        return Container(
          color: Colors.red,
          padding: const EdgeInsets.all(8.0),
          child: Text(carModel?.description ?? ''),
        );
      }
      return const CircularProgressIndicator();
    },
  );
}

Demo 地址

相关推荐
asdfg12589635 分钟前
JS中的闭包应用
开发语言·前端·javascript
kirk_wang7 分钟前
Flutter 导航锁踩坑实录:从断言失败到类型转换异常
前端·javascript·flutter
静小谢1 小时前
前后台一起部署,vite配置笔记base\build
前端·javascript·笔记
用户47949283569151 小时前
改了CSS刷新没反应-你可能不懂HTTP缓存
前端·javascript·面试
往来凡尘1 小时前
Flutter运行iOS26真机的两个问题
flutter·ios
还好还好不是吗2 小时前
老项目改造 vue-cli 2.6 升级 rsbuild 提升开发效率300% upupup!!!
前端·性能优化
sumAll2 小时前
别再手动对齐矩形了!这个开源神器让 AI 帮你画架构图 (Next-AI-Draw-IO 体验)
前端·人工智能·next.js
OpenTiny社区2 小时前
2025OpenTiny星光ShowTime!年度贡献者征集启动!
前端·vue.js·低代码
wangan0942 小时前
不带圆圈的二叉树
java·前端·javascript
狗哥哥2 小时前
从零到一:打造企业级 Vue 3 高性能表格组件的设计哲学与实践
前端·vue.js·架构