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 地址

相关推荐
minglie17 小时前
npm ali-oss库依赖冲突
前端·npm
CryptoPP7 小时前
BSE股票K线数据接入实战:从接口调用到前端图表展示
大数据·前端·网络·人工智能·websocket·网络协议
没落英雄9 小时前
5. 从零开始搭建一个 AI Agent —— 人机协作与中断恢复
前端·人工智能·架构
品尚公益团队10 小时前
C#在asp.net网页开发中的带cookie登录实现
前端·c#·asp.net
没有了遇见11 小时前
AI Agent 是什么?—— 一文理解 LLM、Memory、Skills、Tools、MCP、Workflow,Context
android·前端·程序员
后台开发者Ethan11 小时前
setState组件更新
前端·javascript·react
谙忆102411 小时前
大文件上传实战:前端分片、断点续传、秒传与并发控制怎么落地
前端
浮江雾12 小时前
Flutter第三节----Dart中的数据类型
android·开发语言·学习·flutter·入门·函数
又菜又爱coding12 小时前
Flutter Android 无线调试No supported devices connected
flutter
轻动琴弦12 小时前
VoltTool —— 一站式在线开发者工具平台,69+实用工具免费使用
前端·chrome