Cubit을 사용한 counter구현

순순·2024년 11월 22일

Flutter

목록 보기
10/16

이전 글에서 블록 개념 정리를 했으니 이제 실제로 구현해보자.

블록 공식 홈 튜토리얼을 참고했다.
https://bloclibrary.dev/tutorials/flutter-counter/

흐름


  1. Cubit 작성 (비즈니스 로직)
  1. BlocProvider 사용하여 Cubit 제공
    • Cubit 이나 Bloc을 위젯 트리에 제공
    • 위젯 트리의 하위 위젯들이 Cubit 에 접근할 수 있도록 함
  2. viewPage 에서 Cubit 의 상태 사용
    • BlocBuilder는 Cubit의 상태가 변경될 때 마다 UI를 다시 빌드해준다.
   class CounterPage extends StatelessWidget {
     
     Widget build(BuildContext context) {
       // BlocBuilder를 사용하여 상태를 감지하고 UI를 업데이트
       return Scaffold(
         appBar: AppBar(title: Text('Counter')),
         body: Center(
           child: BlocBuilder<CounterCubit, int>(
             builder: (context, count) {
               return Text('$count', style: TextStyle(fontSize: 24));
             },
           ),
         ),

  1. Cubit 의 상태변화 감지

    • CounterObserver 는 상태가 변경될 때 마다 관찰한다.
    • 옵저버를 설정해주면 로그로 상태를 확인할 수 있다.
    void main() {
      Bloc.observer = CounterObserver(); // 상태 변화를 관찰하도록 설정
      runApp(MyApp());
    }
  1. emit
    • cubit(또는 bloc) 에서 새로운 상태를 내보내는 함수.
    • 상태(state) 가 변경되었음을 알리는 역할을 한다. emit 을 호출하면 해당 cubit 이 새로운 상태를 가지게 되고, 이 상태변화를 감지한 UI나 다른 로직들이 업데이트 된다. (changeNotifier 랑 비슷하다고 생각)

예제 코드


  • bloc 의존성 추가
flutter pub add flutter_bloc

  • counter_observer.dart 파일 생성
import 'package:bloc/bloc.dart';

// BlocObserver 생성
class CounterObserver extends BlocObserver {
  const CounterObserver();

  
  void onChange(BlocBase bloc, Change change) {
    super.onChange(bloc, change);
    print('${bloc.runtimeType} $change');
  }

}

  • main.dart 에서 CounterObserver 를 초기화해준다.
void main() {
  // initializing CounterObserver
  Bloc.observer = const CounterObserver();

  runApp(const MyApp());
}

이제 페이지를 만들러 떠난다


  • 카운터 페이지 (뷰)
import 'package:bloc_provider_test/counter_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

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

  
  Widget build(BuildContext context) {
  // BlocProvider 설정
    return BlocProvider(
    // 여기서 큐빗 객체 생성
      create: (BuildContext context) {
        return CounterCubit();
      },
      child: CounterView(),
    );
  }
}

상태 관리 비즈니스 로직을 cubit 에 작성한다. increment 메서드를 실행하면 emit 를 통해 현재 상태를 +1 업데이트. 생성자를 통해 상태를 0으로 초기화 하고 있기 때문에 상태의 초기값은 0이 된다.


  • counter_cubit.dart
import 'package:bloc/bloc.dart';

class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);

  // add 1 to the current state.
  void increment() => emit(state + 1);

  // subtract 1 from the current state.
  void decrement() => emit(state - 1);

}

플로팅버튼이 클릭되면 cubit의 메서드를 실행한다. context.read() 를 통해 큐빗에 접근할 수 있는 이유는 아까 상위 위젯에서 BlocProdiver 를 통해 해당 큐빗을 등록해주었기 때문.

  • counter_view.dart
import 'package:bloc_provider_test/counter_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

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

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: BlocBuilder<CounterCubit, int>(
            builder: (context, state) {
              return Text('$state');
            }),
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            child: Icon(Icons.add),
            onPressed: () => context.read<CounterCubit>().increment(),
          ),
          SizedBox(height: 8),
          FloatingActionButton(
            child: Icon(Icons.remove),
            onPressed: () => context.read<CounterCubit>().decrement(),
          )
        ],
      ),
    );
  }
}

이제 메인 페이지를 CounterPage로 변경해주면 끝. 앱이 제대로 작동되는 것을 볼 수 있다.

  • main.dart
import 'package:bloc/bloc.dart';
import 'package:bloc_provider_test/counter_observer.dart';
import 'package:bloc_provider_test/counter_page.dart';
import 'package:flutter/material.dart';

void main() {
  // initializing CounterObserver
  Bloc.observer = const CounterObserver();

  runApp(const MyApp());
}

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

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: CounterPage()
    );
  }
}

구현한 모습



옵저버가 콘솔에 이런 식으로 상태를 출력해준다.

profile
플러터와 안드로이드를 공부합니다

0개의 댓글