Chuyển đến nội dung chính

第 7 課:塊圖案和肘節

集團模式、事件、狀態。肘節 vs 塊。 BlocProvider、BlocBuilder、BlocListener、BlocConsumer。 MultiBlocProvider,塊到塊通信。水合塊。

💻 程式設計 — 第 7 課 第 7 課:塊圖案和肘節

Flutter 和 Dart:從基礎到高級

第 2 部分:導航和狀態管理

亞洲開發網

1. Cubit-簡單狀態管理

dependencies:
  flutter_bloc: ^8.1.0
  hydrated_bloc: ^9.1.0
class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);

  void increment() => emit(state + 1);
  void decrement() => emit(state - 1);
  void reset() => emit(0);
}

2. Bloc-事件驅動

// Events
sealed class AuthEvent {}
class AuthLoginRequested extends AuthEvent {
  final String email;
  final String password;
  AuthLoginRequested({required this.email, required this.password});
}
class AuthLogoutRequested extends AuthEvent {}

// States
sealed class AuthState {}
class AuthInitial extends AuthState {}
class AuthLoading extends AuthState {}
class AuthAuthenticated extends AuthState {
  final User user;
  AuthAuthenticated(this.user);
}
class AuthError extends AuthState {
  final String message;
  AuthError(this.message);
}

// Bloc
class AuthBloc extends Bloc<AuthEvent, AuthState> {
  final AuthRepository _authRepository;

  AuthBloc(this._authRepository) : super(AuthInitial()) {
    on<AuthLoginRequested>(_onLogin);
    on<AuthLogoutRequested>(_onLogout);
  }

  Future<void> _onLogin(AuthLoginRequested event, Emitter<AuthState> emit) async {
    emit(AuthLoading());
    try {
      final user = await _authRepository.login(event.email, event.password);
      emit(AuthAuthenticated(user));
    } catch (e) {
      emit(AuthError(e.toString()));
    }
  }

  Future<void> _onLogout(AuthLogoutRequested event, Emitter<AuthState> emit) async {
    await _authRepository.logout();
    emit(AuthInitial());
  }
}

3. BlocProvider、BlocBuilder、BlocListener

// Provide
MultiBlocProvider(
  providers: [
    BlocProvider(create: (_) => AuthBloc(authRepo)),
    BlocProvider(create: (_) => ThemeBloc()),
  ],
  child: const MyApp(),
);

// Build
BlocBuilder<AuthBloc, AuthState>(
  builder: (context, state) => switch (state) {
    AuthLoading() => const CircularProgressIndicator(),
    AuthAuthenticated(:final user) => Text('Welcome ${user.name}'),
    AuthError(:final message) => Text(message),
    _ => const LoginForm(),
  },
);

// Listen — side effects
BlocListener<AuthBloc, AuthState>(
  listener: (context, state) {
    if (state is AuthError) {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(state.message)));
    }
  },
  child: const LoginForm(),
);

// BlocConsumer = Builder + Listener
BlocConsumer<AuthBloc, AuthState>(
  listener: (context, state) {
    if (state is AuthAuthenticated) {
      context.go('/home');
    }
  },
  builder: (context, state) {
    return ElevatedButton(
      onPressed: state is AuthLoading ? null : () {
        context.read<AuthBloc>().add(AuthLoginRequested(email: email, password: password));
      },
      child: state is AuthLoading ? const CircularProgressIndicator() : const Text('Login'),
    );
  },
);

4. 水合塊-持久狀態

class ThemeBloc extends HydratedCubit<ThemeMode> {
  ThemeBloc() : super(ThemeMode.system);

  void toggle() => emit(state == ThemeMode.dark ? ThemeMode.light : ThemeMode.dark);

  @override
  ThemeMode fromJson(Map<String, dynamic> json) =>
      ThemeMode.values[json['mode'] as int];

  @override
  Map<String, dynamic> toJson(ThemeMode state) => {'mode': state.index};
}

下一篇: 表單、驗證和主題。