Flutter/Package

[Flutter] Bloc ② - Cubit 과 Bloc

찌김이 2022. 8. 4. 11:32
728x90
반응형

Bloc ① - 소개  https://dalgoodori.tistory.com/28

Bloc ② - Cubit 과 Bloc

Bloc ③ - Bloc Widgets https://dalgoodori.tistory.com/30

Bloc ④ - context.read, context.watch, context.select https://dalgoodori.tistory.com/31

Bloc ⑤ - Bloc Test https://dalgoodori.tistory.com/32

 

Cubit

  • Cubit 은 Bloc 과 다르게 이벤트 기반이 아니라 정말 간단하게 상태를 관리할 수 있습니다.
  • Provider 의 ChangeNotifier 와 비슷합니다.

 

생성

  • Cubit 을 상속받는 클래스를 만들어주면 됩니다.
  • 초기값은 내부적으로 넣을 수도 있고 initialState 로 외부적으로 초기값을 지정하는 방법도 있습니다.
  • 상태는 emit 을 이용하여 변경합니다.
  • 상태변경이 일어나면 onChange() 로 변경사항을 알 수 있습니다.
  • 에러발생이 일어나면 onError() 로 알 수 있습니다.
import 'package:flutter_bloc/flutter_bloc.dart';

// 초기값은 내부에서
class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);

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

// 초기값은 외부에서
class CounterCubit extends Cubit<int> {
  CounterCubit(int initialState) : super(initialState);

  void increment() => emit(state + 1);
  void decrement() => emit(state - 1);
  
  // 변경 감지
  @override
  void onChange(Change<int> change) {
    super.onChange(change);
    print(change);
  }
  
  // 에러 감지
  @override
  void onError(Object error, StackTrace stackTrace) {
    super.onError(error, stackTrace);
    print('$error, $stackTrace');
  }
}

 

사용

  • Bloc 을 사용할 화면의 부모를 BlocProvider 로 지정하고 사용할 Cubit 을 지정합니다.
  • Bloc 을 사용하는 화면에서 BlocBuilder 를 만들고 UI 를 그려줍니다.
  • Cubit 사용은 context.read<CounterCubit>() 으로 합니다. 
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class BlocScreen extends StatelessWidget {
  const BlocScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_) => CounterCubit(),
      child: BlocCounterScreen()
    );
  }
}

class BlocCounterScreen extends StatelessWidget {
  const BlocCounterScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Bloc(Counter)'),
      ),
      body: BlocBuilder<CounterCubit, int>(
        builder: (context, count) => Center(child: Text('$count')),
      ),
      floatingActionButton: Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          FloatingActionButton(
            child: const Icon(Icons.add),
            onPressed: () => context.read<CounterCubit>().increment(),
          ),
          const SizedBox(height: 4),
          FloatingActionButton(
            child: const Icon(Icons.remove),
            onPressed: () => context.read<CounterCubit>().decrement(),
          ),
        ],
      ),
    );
  }
}

 

 

Bloc

  • 상태변경을 이벤트에 의존하는 클래스 입니다. 
  • Cubit 과 다르게 추적가능하다는 장점을 가지고 있습니다.

 

생성

  • 위의 Cubit 예제인 카운팅 로직을 만들기 위해서 Bloc, Event, State 를 만들어야합니다.
  • 카운팅 앱 같은 경우는 매우 간단하여 State 클래스를 만들지 않고 진행합니다.

 

1. Event

  • abstract class 를 만듭니다.
  • 로직마다 클래스를 만들어주고 만들었던 클래스를 상속시켜 줍니다.
abstract class CounterEvent {}

class CounterIncrementPressed extends CounterEvent {}

class CounterDecrementPressed extends CounterEvent {}

 

2. Bloc

  • Bloc 클래스를 만들고 Bloc<{event}, {state}> 를 상속받습니다.
  • 호출되는 이벤트를 통해 state 가 증감 됩니다.
class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0) {
    on<CounterIncrementPressed>((event, emit) {
      emit(state +1);
    });
    on<CounterDecrementPressed>((event, emit) {
      emit(state -1);
    });
  }
}

 

사용

  • Bloc 을 사용할 화면의 부모를 BlocProvider 로 지정하고 사용할 Bloc 을 지정합니다.
  • Bloc 을 사용하는 화면에서 BlocBuilder 를 만들고 UI 를 그려줍니다.
  • Bloc 사용은 context.read<CounterBloc>() 으로 하고 해당 이벤트들을 호출합니다.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class BlocScreen extends StatelessWidget {
  const BlocScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_) => CounterBloc(), // Bloc 넣기
      child: BlocCounterScreen()
    );
  }
}

class BlocCounterScreen extends StatelessWidget {
  const BlocCounterScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Bloc(Counter)'),
      ),
      body: BlocBuilder<CounterBloc, int>(
        builder: (context, count) => Center(child: Text('$count')),
      ),
      floatingActionButton: Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          FloatingActionButton(
            child: const Icon(Icons.add),
            onPressed: () => context.read<CounterBloc>().add(CounterIncrementPressed()),
          ),
          const SizedBox(height: 4),
          FloatingActionButton(
            child: const Icon(Icons.remove),
            onPressed: () => context.read<CounterBloc>().add(CounterDecrementPressed()),
          ),
        ],
      ),
    );
  }
}

 

728x90
반응형

'Flutter > Package' 카테고리의 다른 글

[Flutter] Bloc ④ - context.read, context.watch, context.select  (0) 2022.08.05
[Flutter] Bloc ③ - Bloc Widgets  (0) 2022.08.04
[Flutter] Bloc ① - 소개  (0) 2022.08.03
[Flutter] Provider  (0) 2022.07.27
[Flutter] Hive  (0) 2022.07.26