Flutter圈子Flutter 入门与实战Flutter中文社区

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

2022-03-18  本文已影响0人  岛上码农

前言

上一篇我们介绍了 GetX 的的简单状态管理 GetBuilder 的使用,本篇我们继续,来在状态管理中完成网络请求后更新界面。我们这一篇来对比一下 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 的差异部分。

// 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(),
    );
  }
}
// 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 了,然后从个人主页增加一个按钮,点击后路由到该页面(见下图,为了区分,我们换了一张背景图)。

屏幕录制2021-09-05 下午9.56.24.gif
这个时候,这个页面其实和上一个页面已经没有任何关系了,但是却依旧可以使用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 具备如下特点:

上一篇 下一篇

猜你喜欢

热点阅读