Flutter状态管理架构插件clean_bloc的使用

Flutter状态管理架构插件clean_bloc的使用

Clean Bloc 是一个围绕 bloc 包构建的封装器,它帮助实现清洁架构设计模式。

开始使用

安装

在你的 pubspec.yaml 文件中添加以下依赖:

dependencies:
  clean_bloc: latest

使用

分页的 Clean Cubit

import 'package:clean_bloc/clean_bloc.dart';
import 'package:clean_network/clean_network.dart';
import 'package:injectable/injectable.dart';

@injectable
class UserCubit extends PaginatedCleanCubit<UserModel> {
  final UserRepository _repository;

  UserCubit(this._repository) {
    init();
  }

  [@override](/user/override)
  Pagination get initialPage =>
      const Pagination.page(currentPage: 1, perPage: 6);

  [@override](/user/override)
  PaginatedEitherResponse<UserModel> Function(Pagination pagination)
      get remoteCall {
    return (pagination) {
      final params = pagination as PagePagination;
      return _repository.getUsers(
        page: params.currentPage,
        limit: params.perPage,
      );
    };
  }
}

Clean Cubit

import 'package:clean_bloc/clean_bloc.dart';
import 'package:clean_network/clean_network.dart';
import 'package:injectable/injectable.dart';

@injectable
class UserCubit extends CleanCubit<UserModel> {
  final UserRepository _repository;

  UserCubit(this._repository) {
    init();
  }

  [@override](/user/override)
  EitherResponse<UserModel> Function() get remoteCall {
    return () => _repository.getUser();
  }
}

创建事件用于 Clean Bloc

import 'package:clean_bloc/clean_bloc.dart';

class UserAddEvent extends CleanEvent {
  [@override](/user/override)
  List<Object?> get props => [];
}

Clean Bloc

import 'package:clean_bloc/clean_bloc.dart';
import 'package:clean_network/clean_network.dart';
import 'package:injectable/injectable.dart';

@injectable
class UserBloc extends CleanBloc<UserModel> {
  final UserRepository _repository;

  UserBloc(this._repository) {
    init();
    on<UserAddEvent>(_handleAddEvent);
  }

  [@override](/user/override)
  EitherResponse<UserModel> Function() get remoteCall {
    return () => _repository.getUser();
  }

  /// 处理 [CleanEventInit] 事件
  FutureOr<void> _handleAddEvent(
      UserAddEvent event, Emitter<CleanState<T>> emit) async {
    // 执行某些操作
  }
}

创建事件用于分页的 Clean Bloc

import 'package:clean_bloc/clean_bloc.dart';

class UserAddEvent extends PaginatedCleanEvent {
  [@override](/user/override)
  List<Object?> get props => [];
}

分页的 Clean Bloc

import 'package:clean_bloc/clean_bloc.dart';
import 'package:clean_network/clean_network.dart';
import 'package:injectable/injectable.dart';

@injectable
class UserBloc extends PaginatedCleanBloc<UserModel> {
  final UserRepository _repository;

  UserBloc(this._repository) {
    init();
    on<UserAddEvent>(_handleAddEvent);
  }

  [@override](/user/override)
  Pagination get initialPage =>
      const Pagination.page(currentPage: 1, perPage: 6);

  [@override](/user/override)
  PaginatedEitherResponse<UserModel> Function(Pagination pagination)
      get remoteCall {
    return (pagination) {
      final params = pagination as PagePagination;
      return _repository.getUsers(
        page: params.currentPage,
        limit: params.perPage,
      );
    };
  }

  /// 处理 [UserAddEvent] 事件
  FutureOr<void> _handleAddEvent(
      UserAddEvent event,
      Emitter<PaginatedCleanState<T>> emit,
      ) async {
    // 执行某些操作
  }
}

使用 Clean Bloc

import 'package:auto_route/auto_route.dart';
import 'package:clean_bloc/clean_bloc.dart';
import 'package:example/src/core/di/injector.dart';
import 'package:example/src/features/users/domain/models/user_model.dart';
import 'package:example/src/features/users/presentation/blocs/list/user_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

[@RoutePage](/user/RoutePage)()
class UsersPage extends StatelessWidget {
  const UsersPage({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => getIt<UserCubit>(),
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Users'),
        ),
        body: const UserList(),
      ),
    );
  }
}

class UserList extends StatelessWidget {
  const UserList({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return NotificationListener<ScrollNotification>(
      onNotification: (notification) {
        if (notification is ScrollEndNotification &&
            notification.metrics.extentAfter == 0) {
          context.read<UserCubit>().fetchMore();
          return true;
        }
        return false;
      },
      child: PaginatedCleanBuilder<UserCubit, UserModel>(
        successBuilder: (context, users, isLoadingMore) {
          if (users.isEmpty) {
            return const Center(
              child: Text('No users found'),
            );
          }
          return ListView.builder(
            itemCount: isLoadingMore ? users.length + 1 : users.length,
            itemBuilder: (context, index) {
              if (index == users.length && isLoadingMore) {
                return const Center(
                  child: CircularProgressIndicator(),
                );
              } else {
                final user = users[index];
                return ListTile(
                  title: Text(user.name),
                  subtitle: Text(user.email),
                );
              }
            },
          );
        },
      ),
    );
  }
}

更多关于Flutter状态管理架构插件clean_bloc的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter状态管理架构插件clean_bloc的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


clean_bloc 是一个基于 Bloc 的状态管理架构插件,旨在帮助开发者更好地组织和维护 Flutter 应用的状态管理代码。它结合了 Clean Architecture 的思想,将业务逻辑与 UI 分离,使得代码更加模块化、可测试和可维护。

以下是如何使用 clean_bloc 插件的基本步骤和示例:

1. 安装 clean_bloc 插件

首先,你需要在 pubspec.yaml 文件中添加 clean_bloc 依赖:

dependencies:
  flutter:
    sdk: flutter
  clean_bloc: ^0.1.0  # 请检查最新版本

然后运行 flutter pub get 来安装依赖。

2. 创建 Clean Architecture 层

Clean Architecture 通常分为以下几层:

  • Presentation Layer: 负责 UI 和用户交互。
  • Domain Layer: 包含业务逻辑和用例。
  • Data Layer: 负责数据获取和存储。

clean_bloc 中,通常会将 Bloc 放在 Presentation Layer 中,而将业务逻辑放在 Domain Layer 中。

3. 创建 Bloc

clean_bloc 中,你可以使用 BlocCubit 来管理状态。以下是一个简单的 Bloc 示例:

import 'package:clean_bloc/clean_bloc.dart';

// 定义事件
abstract class CounterEvent {}

class IncrementEvent extends CounterEvent {}

class DecrementEvent extends CounterEvent {}

// 定义状态
class CounterState {
  final int count;

  CounterState(this.count);
}

// 创建 Bloc
class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(CounterState(0));

  @override
  Stream<CounterState> mapEventToState(CounterEvent event) async* {
    if (event is IncrementEvent) {
      yield CounterState(state.count + 1);
    } else if (event is DecrementEvent) {
      yield CounterState(state.count - 1);
    }
  }
}

4. 在 UI 中使用 Bloc

在 Flutter 的 UI 层,你可以使用 BlocBuilderBlocProvider 来消费 Bloc 的状态。

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_bloc.dart';

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => CounterBloc(),
      child: Scaffold(
        appBar: AppBar(title: Text('Counter Example')),
        body: BlocBuilder<CounterBloc, CounterState>(
          builder: (context, state) {
            return Center(
              child: Text('Count: ${state.count}'),
            );
          },
        ),
        floatingActionButton: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            FloatingActionButton(
              onPressed: () => context.read<CounterBloc>().add(IncrementEvent()),
              child: Icon(Icons.add),
            ),
            SizedBox(height: 8),
            FloatingActionButton(
              onPressed: () => context.read<CounterBloc>().add(DecrementEvent()),
              child: Icon(Icons.remove),
            ),
          ],
        ),
      ),
    );
  }
}

5. 测试 Bloc

clean_bloc 也支持单元测试。你可以使用 bloc_test 包来测试 Bloc 的行为。

import 'package:bloc_test/bloc_test.dart';
import 'package:test/test.dart';
import 'counter_bloc.dart';

void main() {
  group('CounterBloc', () {
    late CounterBloc counterBloc;

    setUp(() {
      counterBloc = CounterBloc();
    });

    blocTest<CounterBloc, CounterState>(
      'emits [1] when IncrementEvent is added',
      build: () => counterBloc,
      act: (bloc) => bloc.add(IncrementEvent()),
      expect: () => [CounterState(1)],
    );

    blocTest<CounterBloc, CounterState>(
      'emits [-1] when DecrementEvent is added',
      build: () => counterBloc,
      act: (bloc) => bloc.add(DecrementEvent()),
      expect: () => [CounterState(-1)],
    );
  });
}
回到顶部