Flutter插件vessel的介绍与使用

Flutter插件vessel的介绍与使用

vessel 是一个为 Dart 和 Flutter 设计的 IoC 容器。本文将详细介绍如何使用 vessel 插件,并提供完整的示例代码。

导航

如何与 Riverpod 不同?

  • 它不是一个状态管理解决方案。
  • 只有两种类型的提供者。
  • 不需要指定 dependencies 来实现正确的范围。

如何与 GetIt 不同?

  • 类型安全的工厂(不再需要 param1 和 param2)。
  • 提供者在编译时注册。
  • 能够以类型安全的方式多次注册相同类型。

开始使用

首先,定义一个提供者作为全局变量:

class Counter {
    final int count = 0;
}

final counterProvider = Provider((read) => Counter());

然后,创建容器——它保存所有可提供对象:

final container = ProviderContainer();

最后,读取提供者:

void main() {
    /// Counter 是懒惰创建并缓存在容器中的
    final counter = container.read(counterProvider);
    final sameCounter = container.read(counterProvider);

    print(counter == sameCounter); // true
    print(counter.count); // 0
}

特性

提供者

vessel 中有两种类型的提供者:

class Counter {}
class UserViewModel {
    final int userId;
    UserViewModel(this.userId);
}

// 提供者
final counterProvider = Provider((_) => Counter());

// 工厂提供者
final userVmProvider = Provider.factory(
    (_, int userId) => UserViewModel(userId),
);

这两种提供者的区别在于,Provider.factory 创建提供者,而普通的提供者是自包含的。

考虑 Provider 的用法:

container.read(counterProvider); // Counter 实例

Provider.factory 的用法:

final user100Provider = userVmProvider(100);
container.read(user100Provider);

或者直接:

container.read(userVmProvider(100)) // UserVM.userId === 100
注入提供者
final cartRepositoryProvider = Provider(
    (_) => CartRepository(),
);

final cartViewModelProvider = Provider.factory((read, int cartId) {
    final repository = read(cartRepository);
    return CartViewModel(
        repository: repository,
        cartId: cartId,
    );
});
处置提供者
final cartViewModelProvider = Provider(
    (read) =>  CartViewModel(...),
    dispose: (CartViewModel vm) => vm.dispose(),
);

容器有一个 dispose 方法,可以释放其中的所有提供者。

container.dispose();

覆盖

你可以用任何其他兼容类型的提供者来覆盖任何提供者。

final container = ProviderContainer(
    overrides: [
        userRepositoryProvider.overrideWith(mockUserRepositoryProvider)
    ]
);

container.read(userRepositoryProvider); // MockUserRepository
示例

考虑以下代码:

class UserRepository {
    User getById(int id) {
        return User(id: id, isAdmin: false);
    }
}

class UserProfileViewModel {
    final UserRepository repository;
    final int userId;
    
    UserProfileViewModel({
        required this.repository, 
        required this.userId,
    });

    String get isAdmin => repository.getById(userId).isAdmin;
}

final userRepositoryProvider = Provider(
    (_) => UserRepository(),
);

final userProfileVmProvider = Provider.factory(
    (read, int userId) => UserProfileViewModel(
        userId: userId,
        repository: read(userRepositoryProvider),
    )
);

任务:模拟 UserRepository,使 getById 总是返回管理员用户。

class MockUserRepository implements UserRepository {
    User getById(int id) {
        return User(id: id, isAdmin: true);
    }
}

final mockRepositoryProvider = Provider<UserRepository>(() => MockUserRepository());

final containerWithOverride = ProviderContainer(
    overrides: [
        userRepositoryProvider.overrideWith(mockRepositoryProvider),
    ],
);

void main() {
    final profileVm = containerWithOverride.read(userProfileVmProvider(1));
    print(profileVm.isAdmin); // true
}

作用域

提供者可以作用域化:

final userProvider = Provider((_) => User(...));
final containerRoot = ProviderContainer();
final containerChild = ProviderContainer(
    overrides: [userProvider.scope()],
    parent: containerRoot,
);

void main() {
    final rootUser = containerRoot.read(userProvider);
    final childUser = containerChild.read(userProvider);

    identical(rootUser, childUser); // false
}

provider.scope() 实际上等同于 provider.overrideWith(provider),因此作用域化和覆盖基本上是相同的操作。

提供者会成为作用域化的,如果它的任何依赖项被作用域化。考虑以下示例:

class Counter {
    final int count;
    Counter(this.count);
}

final provider1 = Provider((_) => Counter(1));
final provider2 = Provider((read) => Counter(read(provider1).count + 1));
final provider3 = Provider((read) => Counter(read(provider2).count + 3));

final container = ProviderContainer();
final containerChild = ProviderContainer.scoped(
    [provider2],
    parent: container, 
);

void main() {
    // 现在 provider3 也在 containerChild 中作用域化
    final instance3 = containerChild.read(provider3); 
    final rootInstance3 = container.read(provider3);

    identical(instance3, rootInstance3); // false

    final instance1 = containerChild.read(provider1);
    final rootInstance1 = container.read(provider1);

    // provider1 没有作用域化的依赖项,所以它不会成为作用域化的。
    identical(instance1, rootInstance1); // true
}
依赖关系
final provider1 = Provider((_) => Counter(1));
final provider2 = Provider((read) => Counter(read(provider1).count + 1));
final provider3 = Provider((read) => Counter(read(provider2).count + 3));

更多关于Flutter插件vessel的介绍与使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter插件vessel的介绍与使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,vessel 是一个相对较少人知的插件,因此它的功能和用法可能并不像其他主流插件那样被广泛记录或讨论。为了探索和使用 vessel 插件,你可以按照以下步骤进行:

1. 查找插件的官方文档或源代码

  • Pub.dev: 首先,你可以在 pub.dev 上搜索 vessel 插件,查看是否有官方文档或说明。
  • GitHub: 如果插件是开源的,你可以在 GitHub 上找到它的源代码和可能的文档。

2. 安装插件

pubspec.yaml 文件中添加 vessel 插件的依赖项:

dependencies:
  flutter:
    sdk: flutter
  vessel: ^版本号

然后运行 flutter pub get 来安装插件。

3. 导入插件

在你的 Dart 文件中导入 vessel 插件:

import 'package:vessel/vessel.dart';
回到顶部