入门flutter,状态库到底用哪个!

入门flutter,状态库到底用哪个!

我之前没写过flutter,进了新公司要求使用flutter。由于对flutetr的生态不熟悉,常常感到疑惑,我到底该用哪个库。其中最有争议的就是状态库的选择,在查找了诸多资料和群里询问交流后,写下了这篇文章,对我所接触到的一些flutter库进行调研。

经过查找资料和群友交流推荐,我现在有两个备选方案,一个是provider,一个是getx,provider是官方推荐,但感觉不是很好用,getx网友褒贬不一,还说什么初学者用了getx就废了(笑哭),让我不知该如何是好,令刚开始接触flutter的我甚为纠结,因为我都不熟悉,后来又了解到provider的作者还写了一个更好用的库riverpod,去了解了一下,然后现在选择就变成了getx or riverpod。

由于一时之间不能决定,于是我决定分开两个分支来写,一个使用riverpod + flutter_hooks,一个用getx。

使用riverpod + flutter_hooks

需要安装的依赖:flutter pub add hooks_riverpod flutter_hooks 这个写法使用的hook对于react和vue3开发者非常的友好,符合使用习惯,最重要的是很方便。

写法如下:

使用HookConsumerWidget,定义一个响应式更新到变量使用useState: final isButtonDisabled = useState<bool>(false);,这样就可以愉快的使用定义的变量了,页面会响应式更新的。

class EmailVerificationScreen extends HookConsumerWidget {
  final Map<String, dynamic>? arguments;

  const EmailVerificationScreen(this.arguments, {super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final formKey = useMemoized(() => GlobalKey<FormState>());
    final emailCodeController = useTextEditingController();

    final isButtonDisabled = useState<bool>(false);

    Future<void> nextStep(BuildContext context) async {
      try {
        SRouter(context).pushNamed("SetPassword", queryParameters: {
          "account": arguments?['account'],
        });
      } catch (e) {
        print(e);
      }
    }

    useEffect(() {
      listener() {
        isButtonDisabled.value = emailCodeController.text.length < 6;
      }

      emailCodeController.addListener(listener);
      return () {
        emailCodeController.removeListener(listener);
      };
    }, [emailCodeController]);

    return Form(
      key: formKey,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            S.of(context).emailVerification,
            style: TextStyle(fontSize: 18.sp, fontWeight: FontWeight.w400),
          ),
          SizedBox(height: 8.w),
          Text(
            S.current
                .enterThe6DigitVerificationCodeReceivedInYourEmailTheCodeIsValidFor30Minutes,
            style: TextStyle(
              color: const Color.fromRGBO(143, 143, 143, 1),
              fontSize: 12.sp,
              fontWeight: FontWeight.w400,
            ),
          ),
          SizedBox(height: 39.w),
          SStyledInput(
            controller: emailCodeController,
            labelText: S.of(context).emailVerificationCode,
            validator: (value) => Validators.validateEmail(value, context),
          ),
          SizedBox(height: 10.w),
          SizedBox(
            height: 50.w,
            width: double.infinity,
            child: ElevatedButton(
              onPressed:
                  isButtonDisabled.value ? null : () => nextStep(context),
              child: Text(S.of(context).nextStep),
            ),
          ),
          SizedBox(
            height: 26.w,
          ),
          GestureDetector(
            onTap: () {
              SRouter(context).pushNamed("Register");
            },
            child: Text(
              S.of(context).didNotReceiveTheCode,
              style: const TextStyle(
                color: Color.fromRGBO(79, 160, 255, 1.0),
                fontSize: 12,
              ),
            ),
          )
        ],
      ),
    );
  }
}
 

  • 全局状态管理:

大体如下,使用一个全局的NotifierProvider

final userProvider = NotifierProvider<UserProvide, UserState>(UserProvide.new);

class UserState {
  /// 当前活跃用户
  User? activeUser;

  /// 多用户会话管理
  List<User> userList = [];

  String? get getToken {
    return activeUser?.accessToken;
  }
}

class UserProvide extends Notifier<UserState> {
  @override
  UserState build() => UserState();

  /// 登录
  Future<void> login(User user) async {
    final existingUser =
        state.userList.firstWhereOrNull((u) => u.userId == user.userId);
 

getx

getx是使用的false.obs的形式

var isButtonDisabled = false.obs;

路由对比

由于getx还有路由的相关功能,所以这里再加一个getx 路由和go_router的对比,go_router是官方推荐的。

getx router

  • router.dart getx路由提供了一些转场动画,挺方便的

const Transition transition = Transition.rightToLeft;

List<GetPage> routes = [
  GetPage(
      name: '/',
      page: () => const HomeScreen(username: ''),
      transition: transition),
  GetPage(
      name: '/login',
      page: () => const DefaultLayout(
            title: LocaleKeys.login,
            child: LoginScreen(),
          ),
      transition: transition),
  GetPage(
      name: '/welcomeBack',
      page: () => DefaultLayout(
            title: LocaleKeys.welcomeBack,
            child: WelcomeBackScreen(),
          ),
      transition: transition),
  GetPage(
      name: '/notFound',
      page: () => const NotFoundScreen(),
      transition: Transition.fade),
];

 

  • 跳转:

可以看到getx并没有依赖context

Get.toNamed( '/welcomeBack', arguments: {'email': email}, );

go_router

这里要吐槽一句go_router的官方文档容易让人误解。上来就让人context.go('/users/123'),也没说清楚一点,这个操作数据是不进入路由栈的。所以路由回退不了,让我疑惑半天,差点就换库了,和群友交流了一下才晓得,不少哥们都被坑过。

  • index.dart

final goRouter = GoRouter(
  initialLocation: FlutterConfig.initialLocation,
  redirect: routeBeforeHook,
  // debugLogDiagnostics: true,
  routes: baseRoutes + whiteList,
);

  • routes.dart

List<GoRoute> baseRoutes = [  GoRoute(
  name: "Home",
  path: '/',
  builder: (context, state) => const HomeScreen(),
),];

  • 跳转:

context.pushNamed(name);

  • 这里需要说一下的就是go_router配合riverpod的使用,如何在go_router里面拿到riverpod的状态:

String? routeBeforeHook(BuildContext context, GoRouterState state) {
  final userState = ProviderScope.containerOf(context).read(userProvider);

  if (userState.getToken == null &&
      !whiteList.map((e) => e.path).contains(state.uri.path)) {
    return '/login';
  } else {
    return null;
  }
}

 

国际化对比

getx

如果使用getx的国际化功能,建议配合getx_cli使用,因为这个可以根据json文件生成,json是通用文件,可以方便替换和多项目使用,而且生成之后就有提示了。

import 'package:get/get.dart';

class Messages extends Translations {
  @override
  Map<String, Map<String, String>> get keys => {
        'zh_CN': {
          'hello': '你好 世界',
        },
        'de_DE': {
          'hello': 'Hallo Welt',
        }
      };
}

 

  • 使用:

这个使用方式虽然也方便,但是没有提示

Text('title'.tr);

flutter_localizations

这是官方推荐的,配合编辑器插件Flutter Intl使用。在lib目录下创建I10n文件夹,使用的是.arb后缀的文件,这个文件的格式和json一模一样,插件就会自动帮助生成相应代码了。

总结

总结下来,于我来说大概就是两条路线,一条是散装自定义路线hooks_riverpod + fluter_hooks + go_route + flutter_localizations,一条就是getx全家桶一把梭。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值