플러터에서 Cubit 상태 관리 사용하는 방법

플러터에서 Cubit 상태 관리 사용하는 방법
Cozy CodingPosted On Jun 21, 20248 min read

Cubit State Management in Flutter

상태 관리는 모바일 앱 개발에서 중요한 요소이며, 특히 UI가 반응적인 Flutter와 같은 프레임워크에서는 더욱 중요합니다. Flutter에서 다양한 상태 관리 기술 중 하나인 BLoC (Business Logic Component) 패턴이 상당한 인기를 얻었습니다. BLoC의 영역 내에서 두 가지 주요 접근 방식이 있습니다: Bloc State Management과 Cubit State Management.

Cubit이란?

Cubit은 BLoC 패턴의 일부인 간단하고 직관적인 상태 관리 솔루션입니다. "Business Logic Component"의 약자입니다. 전통적인 BLoC와는 달리, Cubit은 더 가벼우며 더 간단한 API를 가지고 있어 더 작은 프로젝트나 간단한 상태 관리 필요에 쉽게 사용할 수 있습니다.

플러터에서 Cubit 상태 관리를 시작하려면 flutter_bloc 패키지를 설치해야 합니다:

dependencies:
   flutter_bloc: ^8.1.3

Cubit을 사용한 카운터 앱

더 나은 이해를 위해 Cubit을 사용하여 간단한 카운터 앱을 구현해 봅시다. 단계별로 진행하겠습니다. 함께 따라와 주세요.

친구야, Cubit 폴더를 만들어 그 안에 counter_cubit.dart 파일을 생성해보세요.

이미지

파일 안에 Cubit을 확장한 클래스를 만들어주세요.

class CounterCubit extends Cubit {}

문제: 하지만 이렇게 하면 오류가 발생합니다. 수퍼 클래스 'Cubitdynamic'에는 인수가 없는 생성자가 없습니다.

그래서 생성자를 만들어 초기 상태를 전달해야 합니다.

class CounterCubit extends Cubit {
  CounterCubit():super(0);
}

여기서 '0'은 초기 상태이지만 문자열, 클래스 등이 될 수 있습니다.

이제 초기 상태를 화면에 표시해야 합니다

카운터 큐빗 클래스의 인스턴스를 만듭니다.

이제 이 객체를 사용하여 다양한 것에 액세스할 수 있습니다:

Cubit State Management in Flutter

지금은 .state를 필요로 합니다.

final counter = CounterCubit().state;

필요한 곳에서 사용할 수 있습니다.

Text("$counter");

문제: 작은 문제가 있습니다. 이 카운터는 동적 타입이므로 코드를 망가뜨리지는 않지만, 동적 타입을 피해야 합니다.

이미지

그래서 카운터 cubic 클래스에 타입을 지정해 주세요.

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

이제 초기 상태를 성공적으로 표시했어요.

값 증가, 상태 변경

이를 위해 카운터 커빗 클래스에 값을 증가시키는 함수를 만들고 모든 청취자에게 알립니다. 상태를 변경하기 위해 emit 함수를 사용합니다.

emit(state) // 제공된 [state]로 상태를 업데이트합니다.

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

  void increment() {
    emit(state + 1);
  }
}

이제 이 함수를 버튼 클릭에 사용하세요

onPressed: () => CounterCubit().increment(),

문제: 그러나 버튼을 클릭해도 상태가 변경되지 않습니다.

이는 우리가 cubit의 두 개체를 생성하고 있기 때문입니다. 두 번째 cubit의 값을 업데이트하고 있습니다. 이것을 제거하려면 하나의 cubit만 사용해야 합니다.

단일 객체 생성

final counterCubit = CounterCubit();

그리고 이것을 모두에서 사용하세요.

final counter = counterCubit.state; // 빌드 내부

버튼을 누르면

onPressed: () => counterCubit.increment(),

문제점: 그러나 한 가지 더 빠진 것이 있습니다.

한 번만 값을 받아서 상태를 업데이트하고 emit이 청취자에게 통지하지만 우리는 상태를 청취하고 있지 않습니다.

이제 BlocBuilder를 사용해야 합니다. 이는 flutter_bloc에서 제공하는 위젯이며 bloc과 builder라는 두 인수가 필요합니다.

BlocBuilder<CounterCubit, int>(
      bloc: counterCubit, // 선택 사항
      builder: (context, counter) {
         return Text(
           '$counter',
         );
}),

완료 단계

테이블 태그를 Markdown 형식으로 변경해주세요.

Create a separate class extend with cubit, give the initial state and a function to change the state.

import 'package:flutter_bloc/flutter_bloc.dart';

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

  void increment() {
    emit(state + 1);
  }
}

Use the state by making a single object of the cubit class and use BlocBuilder where you need the changing state

class _MyHomePageState extends State<MyHomePage> {
  final counterCubit = CounterCubit(); // (1: object)
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            // (2: state value)
            BlocBuilder<CounterCubit, int>(
              bloc: counterCubit, // optional
              builder: (context, counter) {
                return Text(
                  '$counter',
                );
              }
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => counterCubit.increment(), // (3: increment)
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

감소 기능 추가

 void decrement() {
    if (state == 0) {
      return;
    }
    emit(state - 1);
  }
onPressed: () => counterCubit.decrement(),

참고: emit() 함수는 Cubit 외부에서 사용할 수 없습니다.

질문: 두 개의 별도 페이지가 있는 경우

두 개의 별도 페이지가 있는 경우에는 상태를 표시하는 페이지와 그 상태를 변경하는 버튼이 있는 페이지가 따로 있는 것을 의미합니다.

그런데 앞서 언급한 대로 cubit 클래스의 두 개의 다른 객체를 사용할 수 없습니다.

이미지

이제 icc_dec_page에 버튼이 있고 home_page.dart에서 카운터를 표시하고 있습니다.

카운터 Cubit의 두 인스턴스를 만들 수 없기 때문에 작동하지 않습니다. 하나의 인스턴스만 사용해야 합니다. 이 문제를 해결하기 위해 BlocProvider를 사용합니다. BlocProvider는 블록의 인스턴스를 전달하는 데 사용됩니다.

따라서 main.dart에서 Material app을 BlocProvider로 래핑하고 cubit/bloc을 함수의 인수로 전달합니다.

Markdown 형식의 표로 변경:

Widget build(BuildContext context) { return BlocProvider( // <-- 이 부분 create: (_) => CounterCubit(), child: MaterialApp( title: 'Flutter Demo', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ), ); } }

이제 앱 어디에서든 이 카운터 cubit 인스턴스에 액세스할 수 있습니다. 이전에 생성한 cubit 인스턴스를 제거하고 다음을 사용할 수 있습니다.

final counterCubit = BlocProvider.of<CounterCubit>(context);

home_page.dart에서

  Widget build(BuildContext context) {
    final counterCubit = BlocProvider.of<CounterCubit>(context);
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[

            BlocBuilder<CounterCubit, int>(
                bloc: counterCubit, // optional
                builder: (context, counter) {
                  return Text(
                    '$counter',
                  );
                }),
          ],
        ),
      ),

inc_dec_page.dart 파일에서

 @override
  Widget build(BuildContext context) {
    final counterCubit = BlocProvider.of<CounterCubit>(context);
    return Scaffold(
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          IconButton(
            onPressed: () => counterCubit.increment(),
            tooltip: '증가',
            icon: const Icon(Icons.add),
          ),
          const SizedBox(
            height: 10,
          ),
          IconButton(
            onPressed: () => counterCubit.decrement(),
            tooltip: '감소',
            icon: const Icon(Icons.minimize),
          ),
        ],

이 예시의 전체 코드는 제 GitHub 저장소에서 확인할 수 있습니다:

결론

요약하자면, Cubit은 bloc 및 provider 패키지의 장점을 결합하여 상태를 관리하는 간단한 방법을 제공하며 이벤트의 복잡성 없이 상태를 관리할 수 있습니다. Cubit은 메서드 중심의 접근 방식과 최소한의 보일러플레이트 코드로 상태 관리를 간소화하므로 Flutter 개발자들에게 효율성과 구현 용이성을 위한 탁월한 선택지가 됩니다.

  • 👔 LinkedIn: muhammadnaqeeb
  • 💻 GitHub: muhammadnaqeeb