写点什么

再仿个人主页来看 GetX 和 Provider 之间的 PK

作者:岛上码农
  • 2022 年 6 月 16 日
  • 本文字数:2940 字

    阅读完需:约 10 分钟

再仿个人主页来看 GetX 和 Provider 之间的 PK

前言

上一篇我们介绍了 GetX 的的简单状态管理 GetBuilder 的使用,本篇我们继续,来在状态管理中完成网络请求后更新界面。在我们介绍 Provider 的时候做了一个个人主页:使用 FutureProvider 搞定个人主页异步请求的状态管理,我们这一篇来对比一下 GetXProvider 的差异。

状态代码

这里我们网络请求还是使用 Dio,原先的请求相关的代码我们直接复制过来了,源码可以在这里下载:GetX应用代码。在 VSCode 的编辑界面输入 getcontroller 代码模板指令(需要安装 GetX Snippets 扩展)来说输入状态管理代码。这里我们有两个状态属性,一个是网络请求状态枚举_loadingStatus,用于指示网络请求状态;另一个是掘金的个人信息_personalProfile。在构造方法中我们传递用户 id,来请求个人信息数据。可以看到,实际上的代码和计数器的基本上一样,也是更新状态对象最新值,使用 update 通知界面刷新。存在的差别在于我们引入了 GetxController 的一个生命周期函数 onReady 来进行网络请求。onReady 在 GetX 的说明如下:


Called 1 frame after onInit(). It is the perfect place to enter navigation events, like snackbar, dialogs, or a new route, or async request.在 onInit()之后的一帧调用,非常适合放置导航入口事件,例如 SnackBar,对话框、新的路由或异步请求。


关于 GetxController 的生命周期我们下一篇再具体介绍,目前我们知道 GetX 推荐在 onReady 进行网络请求即可。


enum LoadingStatus {  loading,  success,  failed,}
class PersonalController extends GetxController { static PersonalController get to => Get.find(); final String userId; PersonalController({required this.userId});
@override void onReady() { getPersonalProfile(userId); super.onReady(); }
PersonalEntity? _personalProfile; get personalProfile => _personalProfile;
LoadingStatus _loadingStatus = LoadingStatus.loading; get loadingStatus => _loadingStatus;
void getPersonalProfile(String userId) async { _loadingStatus = LoadingStatus.loading; _personalProfile = await JuejinService.getPersonalProfile(userId); if (_personalProfile != null) { _loadingStatus = LoadingStatus.success; } else { _loadingStatus = LoadingStatus.failed; } update(); }}
复制代码

界面代码

界面代码我们不贴了,我们只来对比和 Provider 的差异部分。


  • 最外层代码:这里当时这么写主要是 Provider 要给下级组件做共享,因此需要有个包裹 Widget。看起来相差不太大。


// GetX 最外层class PersonalHomePageWrapper extends StatelessWidget {  const PersonalHomePageWrapper({Key? key}) : super(key: key);
@override Widget build(BuildContext context) { return GetBuilder<PersonalController>( init: PersonalController(userId: '70787819648695'), builder: (controller) => _PersonalHomePage(), ); }}//Provider 最外层class PersonalHomePageWrapper extends StatelessWidget { const PersonalHomePageWrapper({Key? key}) : super(key: key);
@override Widget build(BuildContext context) { return FutureProvider<PersonalEntity?>( create: (context) => JuejinService.getPersonalProfile('70787819648695'), initialData: null, child: _PersonalHomePage(), ); }}
复制代码


  • 实际页面代码:两部分代码看起来也几乎没差别,都是获取状态对象后再构建页面。这里为了语义更准确,我们这次增加了一个网络加载属性来标识请求。这里看来,如果是从 Provider 切换到 GetX,在使用 GetBuilder 这种简单的呃状态管理方式的话,代码改动量应该会很少。其实两部分代码最大的差别是 GetX 不需要使用 context 来获取状态对象了。


// GetX 代码@override  Widget build(BuildContext context) {    if (PersonalController.to.loadingStatus == LoadingStatus.loading) {      return Center(        child: Text('加载中...'),      );    }    if (PersonalController.to.loadingStatus == LoadingStatus.failed) {      return Center(        child: Text('请求失败'),      );    }    PersonalEntity personalProfile = PersonalController.to.personalProfile;    return Stack(      children: [        CustomScrollView(          slivers: [            _getBannerWithAvatar(context, personalProfile),            _getPersonalProfile(personalProfile),            _getPersonalStatistic(personalProfile),          ],        ),     //...}
// Provider 代码class _PersonalHomePage extends StatelessWidget { const _PersonalHomePage({Key? key}) : super(key: key);
@override Widget build(BuildContext context) { PersonalEntity? personalProfile = context.watch<PersonalEntity?>(); if (personalProfile == null) { return Center( child: Text('加载中...'), ); } return Stack( children: [ CustomScrollView( slivers: [ _getBannerWithAvatar(context, personalProfile), _getPersonalProfile(personalProfile), _getPersonalStatistic(personalProfile), ], ), //...}
复制代码


那么 GetX 的优势在哪里呢?我们来将个人主页的代码复制一份,但是不再使用 GetBuilder 了,然后从个人主页增加一个按钮,点击后路由到该页面(见下图,为了区分,我们换了一张背景图)。



这个时候,这个页面其实和上一个页面已经没有任何关系了,但是却依旧可以使用PersonalController.to.personalProfile访问到个人信息数据。部分代码如下所示:


class PersonalHomePageCopy extends StatelessWidget {  const PersonalHomePageCopy({Key? key}) : super(key: key);
@override Widget build(BuildContext context) { PersonalEntity personalProfile = PersonalController.to.personalProfile; return Stack( children: [ CustomScrollView( slivers: [ _getBannerWithAvatar(context, personalProfile), _getPersonalProfile(personalProfile), _getPersonalStatistic(personalProfile), ], ), //...}
复制代码


这就使得状态数据的复用更加简洁了,只要状态对象被初始化过后,就可以在任何组件使用——不需要组件之间有任何的关联,比如不需要有共同的父级组件。

总结

本篇介绍了在GetX 的状态管理中进行异步请求刷新界面,并和使用Provider进行状态管理的代码。可以看到 GetX 具备如下特点:


  • 异步请求和普通的状态管理没什么差别,方式相当简单;

  • Provider 迁移到 GetX 修改的代码量不多;

  • GetX 的状态共享方式更简单,无需组件之间有任何关联,只要状态对象被初始化了,就可以在任何组件访问。这才是 GetX 真正的优势所在。


发布于: 刚刚阅读数: 4
用户头像

岛上码农

关注

用代码连接孤岛,公众号@岛上码农 2022.03.03 加入

从南漂到北,从北漂到南的业余码农

评论

发布
暂无评论
再仿个人主页来看 GetX 和 Provider 之间的 PK_flutter_岛上码农_InfoQ写作社区