0%

Flutter 状态路径一次性描述

看来新的项目有用到之前没用过的库,所以需要了解一下。

各个状态库描述

riverpod,riverpod-annotation,flutter hook,hooks-riverpod 这些有没有类似递进的关系,这样的话,我好一步一步了解,你也可以补充我漏掉的环节

让我帮你梳理这些库的递进关系和学习路径:

  1. riverpod (基础库)

    • 这是最基础的库,提供了核心的状态管理功能
    • 主要概念:Provider, StateNotifier, ProviderContainer
    // 基础写法
    final counterProvider = StateNotifierProvider<Counter, int>((ref) {
    return Counter();
    });

    class Counter extends StateNotifier<int> {
    Counter() : super(0);
    void increment() => state++;
    }
  2. flutter_riverpod (Flutter 集成)

    • riverpod 基础上增加了 Flutter 集成
    • 提供了 ConsumerWidget, ConsumerStatefulWidget 等
    class MyWidget extends ConsumerWidget {
    @override
    Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Text('$count');
    }
    }
  3. riverpod_annotation (简化语法)

    • 通过代码生成简化 Provider 的创建
    • 引入了 @riverpod 注解
    @riverpod
    class Counter extends _$Counter {
    @override
    int build() => 0;
    void increment() => state++;
    }
  4. flutter_hooks (状态逻辑复用)

    • 提供了一种新的状态管理方式
    • 主要用于复用状态逻辑
    class Example extends HookWidget {
    @override
    Widget build(BuildContext context) {
    final controller = useTextEditingController();
    return TextField(controller: controller);
    }
    }
  5. hooks_riverpod (完整集成)

    • 结合了 flutter_riverpodflutter_hooks
    • 提供了 HookConsumerWidget 等组件
    class Example extends HookConsumerWidget {
    @override
    Widget build(BuildContext context, WidgetRef ref) {
    final controller = useTextEditingController();
    final count = ref.watch(counterProvider);
    return TextField(controller: controller);
    }
    }

学习建议:

  1. 先学习 riverpod 的核心概念
  2. 了解 flutter_riverpod 如何与 Flutter 集成
  3. 学习使用 riverpod_annotation 简化代码
  4. 如果需要处理复杂状态逻辑,学习 flutter_hooks
  5. 最后掌握 hooks_riverpod 的完整功能

补充一些重要的中间环节:

  1. Provider 的不同类型:

    • Provider
    • StateProvider
    • StateNotifierProvider
    • FutureProvider
    • StreamProvider
  2. 状态管理的模式:

    • 依赖注入
    • 状态监听
    • 状态修改
  3. 生命周期管理:

    • autoDispose
    • family
    • 缓存策略

这样的学习路径会让你逐步深入理解整个生态系统。每一步都建立在前一步的基础上,让学习过程更加自然。

状态库实现对比

你给出一个最小验证例子,包含每一个库的单独的使用,基本实现相同的功能的页面,这样我就能更好的理解了

我来帮你创建一个简单的计数器页面,用不同的库来实现,这样你就能看到它们的区别。

  1. 使用纯 riverpod:

    // main.dart
    import 'package:flutter/material.dart';
    import 'package:riverpod/riverpod.dart';

    // 定义 provider
    final counterProvider = StateNotifierProvider<Counter, int>((ref) => Counter());

    class Counter extends StateNotifier<int> {
    Counter() : super(0);
    void increment() => state++;
    }

    void main() {
    runApp(
    ProviderScope(
    child: MyApp(),
    ),
    );
    }

    class CounterPage extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    return Scaffold(
    appBar: AppBar(title: Text('Riverpod Counter')),
    body: Center(
    child: Consumer(
    builder: (context, ref, child) {
    final count = ref.watch(counterProvider);
    return Text('Count: $count');
    },
    ),
    ),
    floatingActionButton: Consumer(
    builder: (context, ref, child) {
    return FloatingActionButton(
    onPressed: () => ref.read(counterProvider.notifier).increment(),
    child: Icon(Icons.add),
    );
    },
    ),
    );
    }
    }
  2. 使用 flutter_riverpod:

    // main.dart
    import 'package:flutter/material.dart';
    import 'package:flutter_riverpod/flutter_riverpod.dart';

    final counterProvider = StateNotifierProvider<Counter, int>((ref) => Counter());

    class Counter extends StateNotifier<int> {
    Counter() : super(0);
    void increment() => state++;
    }

    void main() {
    runApp(
    ProviderScope(
    child: MyApp(),
    ),
    );
    }

    class CounterPage extends ConsumerWidget {
    @override
    Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);

    return Scaffold(
    appBar: AppBar(title: Text('Flutter Riverpod Counter')),
    body: Center(
    child: Text('Count: $count'),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => ref.read(counterProvider.notifier).increment(),
    child: Icon(Icons.add),
    ),
    );
    }
    }
  3. 使用 riverpod_annotation:

    // counter_provider.dart
    import 'package:riverpod_annotation/riverpod_annotation.dart';

    part 'counter_provider.g.dart';

    @riverpod
    class Counter extends _$Counter {
    @override
    int build() => 0;

    void increment() => state++;
    }

    // main.dart
    import 'package:flutter/material.dart';
    import 'package:flutter_riverpod/flutter_riverpod.dart';
    import 'counter_provider.dart';

    void main() {
    runApp(
    ProviderScope(
    child: MyApp(),
    ),
    );
    }

    class CounterPage extends ConsumerWidget {
    @override
    Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);

    return Scaffold(
    appBar: AppBar(title: Text('Riverpod Annotation Counter')),
    body: Center(
    child: Text('Count: $count'),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => ref.read(counterProvider.notifier).increment(),
    child: Icon(Icons.add),
    ),
    );
    }
    }
  4. 使用 flutter_hooks:

    // main.dart
    import 'package:flutter/material.dart';
    import 'package:flutter_hooks/flutter_hooks.dart';

    void main() {
    runApp(MyApp());
    }

    class CounterPage extends HookWidget {
    @override
    Widget build(BuildContext context) {
    final counter = useState(0);

    return Scaffold(
    appBar: AppBar(title: Text('Flutter Hooks Counter')),
    body: Center(
    child: Text('Count: ${counter.value}'),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: () => counter.value++,
    child: Icon(Icons.add),
    ),
    );
    }
    }
  5. 使用 hooks_riverpod:

    // counter_provider.dart
    import 'package:riverpod_annotation/riverpod_annotation.dart';

    part 'counter_provider.g.dart';

    @riverpod
    class Counter extends _$Counter {
    @override
    int build() => 0;

    void increment() => state++;
    }

    // main.dart
    import 'package:flutter/material.dart';
    import 'package:hooks_riverpod/hooks_riverpod.dart';
    import 'counter_provider.dart';

    void main() {
    runApp(
    ProviderScope(
    child: MyApp(),
    ),
    );
    }

    class CounterPage extends HookConsumerWidget {
    @override
    Widget build(BuildContext context, WidgetRef ref) {
    // 使用 hooks 来管理本地状态
    final isEnabled = useState(true);
    // 使用 riverpod 来管理全局状态
    final count = ref.watch(counterProvider);

    return Scaffold(
    appBar: AppBar(title: Text('Hooks Riverpod Counter')),
    body: Center(
    child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
    Text('Count: $count'),
    Switch(
    value: isEnabled.value,
    onChanged: (value) => isEnabled.value = value,
    ),
    ],
    ),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: isEnabled.value
    ? () => ref.read(counterProvider.notifier).increment()
    : null,
    child: Icon(Icons.add),
    ),
    );
    }
    }
  6. 使用 provider

    // 1. Provider Version
    // main.dart
    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';

    // 定义数据模型
    class CounterModel with ChangeNotifier {
    int _count = 0;
    int get count => _count;

    void increment() {
    _count++;
    notifyListeners();
    }
    }

    void main() {
    runApp(
    ChangeNotifierProvider(
    create: (context) => CounterModel(),
    child: MyApp(),
    ),
    );
    }

    class CounterPage extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    return Scaffold(
    appBar: AppBar(title: Text('Provider Counter')),
    body: Center(
    child: Consumer<CounterModel>(
    builder: (context, counter, child) {
    return Text('Count: ${counter.count}');
    },
    ),
    ),
    floatingActionButton: Consumer<CounterModel>(
    builder: (context, counter, child) {
    return FloatingActionButton(
    onPressed: () => counter.increment(),
    child: Icon(Icons.add),
    );
    },
    ),
    );
    }
    }
  7. 使用 pure flutter

    // 2. Pure Flutter Version (StatefulWidget)
    // main.dart
    import 'package:flutter/material.dart';

    void main() {
    runApp(MyApp());
    }

    class CounterPage extends StatefulWidget {
    @override
    _CounterPageState createState() => _CounterPageState();
    }

    class _CounterPageState extends State<CounterPage> {
    int _count = 0;

    void _increment() {
    setState(() {
    _count++;
    });
    }

    @override
    Widget build(BuildContext context) {
    return Scaffold(
    appBar: AppBar(title: Text('Pure Flutter Counter')),
    body: Center(
    child: Text('Count: $_count'),
    ),
    floatingActionButton: FloatingActionButton(
    onPressed: _increment,
    child: Icon(Icons.add),
    ),
    );
    }
    }

主要区别:

  1. riverpod: 需要使用 Consumer 包装需要访问状态的 Widget
  2. flutter_riverpod: 提供了 ConsumerWidget 简化代码
  3. riverpod_annotation: 使用代码生成简化 provider 的创建
  4. flutter_hooks: 用于管理本地状态,提供了很多内置的 hooks
  5. hooks_riverpod: 结合了 hooks 和 riverpod 的优点

要运行这些例子,需要在 pubspec.yaml 中添加对应的依赖:

dependencies:
flutter:
sdk: flutter
riverpod: ^2.5.1
flutter_riverpod: ^2.5.1
riverpod_annotation: ^2.3.0
flutter_hooks: ^0.20.5
hooks_riverpod: ^2.5.1

dev_dependencies:
build_runner: ^2.4.8
riverpod_generator: ^2.3.5

每个实现都完成了相同的基本功能,但使用了不同的方式。从中你可以看到代码的演进和简化过程。