Cubit 변수 vs State 변수 활용 전략


Cubit 내부 변수 사용

  • 용도: 데이터 캐싱, 여러 화면에서 공유되는 값, 필수로 UI에 직접 emit하지 않아도 되는 값
  • 예시: API로 가져온 리스트, 마지막 조회 timestamp, 로그인된 사용자 정보
  • 특징
    • Cubit 내부에 저장
    • state는 단순히 로딩/성공/실패 같은 상태 플래그만 담음
    • UI는 getIt().value 또는 Cubit 필드 직접 접근으로 값 사용
    • emit을 통해 rebuild를 최소화 가능

State 내 변수 사용

  • 용도: 화면에서 즉시 반영해야 하는 값, 상태와 UI를 함께 전달할 때
  • 예시: “조회 성공 → 표시할 데이터”, 에러 메시지, 로딩 여부
  • 특징
    • Immutable state 객체에 값 포함
    • emit을 통해 새 state를 만들어 UI에 전달
    • BlocBuilder/BlocListener가 state 변화에 따라 자동으로 rebuild





BlocBuilder 안/밖에서 재빌드 차이


BlocBuilder 밖

  • 재빌드 조건 : setState() 호출 (build 메서드가 다시 불리기 때문에 전체 위젯 갱신)
  • emit()으로 state가 바뀌거나, Cubit.value가 바뀌어도 재빌드 되지 않는다.

BlocBuilder 안

  • 재빌드 조건 : emit()하여 state가 바뀔 때
  • 같은 state를 emit()하거나 Cubit.value만 바뀌면 재빌드 되지 않는다.

git으로 flutter 버전 관리하기

 

기존 프로젝트 스펙에 맞춰 flutter 버전을 낮춰서 사용해야할 때 설정해야할 것들을 정리해봤다.

 

 

그동안에 homebrew로 flutter를 설치해 사용했기 때문에 지우고 다시 git clone으로 flutter를 설치한다.

homebrew로 설치하게 되면 빌드된 압출본을 통채로 설치하는 방식이라

.git 폴더가 없고 git 명령어를 사용할 수 없다.

 

git clone 설치

git clone https://github.com/flutter/flutter.git

 

셀 설정 파일에 flutter 경로 등록

# Flutter PATH
export PATH="$HOME/flutter/bin:$PATH"

 

설정 파일 저장

source ./.zshrc

 

 

어떤 설정파일을 수정해야할지 모르겠다면,

더보기

현재 터미널 셀 확인 (macOS Catalina 이상은 기본 zsh)

echo $SHELL

/bin/zsh → zsh 사용 중 → ~/.zshrc 설정 파일만 읽음

/bin/bash → bash 사용 중 → ~/.bash_profile 설정 파일만 읽음

 

 

 

 

특정 버전의 소스 코드를 지정하여 사용하더라도 채널 별로 차이가 있을 수 있다고 한다.

특정 버전으로 체크아웃해서 사용하는 경우, 채널은 고려하지 않아도 된다.

더보기

flutter 채널 분류

채널 특징
stable 가장 안정적, 주로 릴리즈용 버전
beta 어느 정도 안정성을 보장하면서  기능 미리 테스트 가능
dev   자주 업데이트, 실험적인 기능 포함 가능
master / main 최신 코드베이스, 가장 자주 바뀌고 안정성은 보장되지 않음

 

 

현재 channel이 안정적인 stable 채널인지 확인하고 아니라면 변경해준다.

 

flutter 채널 정보 확인

flutter channel

출력>

Flutter channels:
* master (latest development branch, for contributors)
  main (latest development branch, follows master channel)
  beta (updated monthly, recommended for experienced users)
  stable (updated quarterly, for new users and for production app releases)

 

stable 채널로 변경

flutter channel stable

 

 

flutter가 설치된 경로로 이동한 후 사용하려는 버전의 소스코드에 체크아웃 한다.

 

flutter 설치 경로 확인

which flutter

 

flutter 버전 변경

git checkout x.xx.x

 

 

이 후 flutter doctor나 flutter --version 명령어로 현재 사용중인 flutter 버전이 바뀐 걸 확인 할 수 있다.

 

flutter 버전 확인

flutter --version

출력>

Flutter x.xx.x • channel [user-branch] • unknown source
Framework • revision c236373904 (7 months ago) • 2025-03-13 16:17:06 -0400
Engine • revision 18b71d647a
Tools • Dart 3.7.2 • DevTools 2.42.3

 

unknown source로 뜨는건 왜 그런지 모르겠다.

flutter channel 명령어로 관리 되는 채널의 브랜치를 따라가는 게 아니라,

특정 flutter 버전의 tag(커밋) 시점의 소스코드를 사용하고 있기 때문에 channel [user-branch] unknwn source로 확인 된다.

Bloc 상태관리 (Cubit)

 

BlocBuilder를 사용하려면 BlocProvider를 부모 위젯으로 둬야한다.

BlocProvider(
  create: (context) => Cubit(),
  child: 
    ...
    BlocBuilder<Cubit, State>(
        builder: (context, state) => Container()
    ),
),

 

 

BlocBuilder.bloc 파라미터에 Cubit을 명시하면 BlocProvider 없이 BlocBuilder를 사용할 수 있다.

단, BlocProvider는 화면 생명주기에 맞춰 Cubit을 관리해주기 때문에, 해당 방식은 수동으로 Cubit.close() 해줘야한다.

BlocBuilder<Cubit, State>(
    bloc: Cubit(),
    builder: (context, state) => Container()
),

예시 코드 처럼 BuilderProvider에서 Cubit을 생성하듯이 생성자를 바로 주입하면,

BlocBuilder가 리빌드 될 때마다 새로운 Cubit이 생성되고 이전 Cubit은 dispose 되지 않아 메모리 누수 가능성이 있다.

최소 멤버 변수로 사용해야한다.

 

 

 

 

Get It 의존성주입

 

두개 이상의 화면에서 같은 상태를 공유하려면 Cubit을 싱글톤으로 등록해 사용하면 편하다.

필요한 시점에 get<Cubit>()으로 바로 가져올 수 있다.

GetIt get = GetIt.instance;

initDi() {
  get.registerLazySingleton<Cubit>(() => Cubit());
}
BlocBuilder<Cubit, State>(
    bloc: get<Cubit>(),
    builder: (context, state) => Container()
),

 

 

Cubit을 사용하지 않는 경우, 상태를 초기화하는 방식을 사용한다.

class Cubit extends Cubit<State> {
  Cubit() : super(CubitInitial());
  
  void reset() => emit(CubitInitial());
}

 

AnimationController

  • AnimationController.value
    • 진행상태로, 1이면 애니메이션이 끝난 상태
  • TweenSequenceItem.weight
    • 해당 Sequence weight 값 / 총 Sequence의 weight 값 비율로 계산된 delay
  • AnimatedSwitcher.transitionBuilder
    • animation: 현재 child가 등장할 때만 동작
    • 이전 child는 previousChildren로만 전달되고, 애니메이션은 직접 따로 작성해야 함
  • PageTransitionSwitcher.transitionBuilder
    • animation: 현재 페이지의 등장 애니메이션
    • secondaryAnimation: 이전 페이지의 퇴장 애니메이션
    • 페이지 전환에 최적화 됨



콜백 타입

  • 위젯 트리를 분리했을 때, 하위 위젯에서 발생한 이벤트나 값 변경을 상위 위젯에 알려주기 위해 사용
  • 상위 위젯 : 콜백함수가 호출 됐을 때, 실행할 로직을 정의
  • 하위 위젯 : 적절한 타이밍에 콜백 함수 호출
  • ValueChanged
    typedef ValueChanged<T> = void Function(T value);
    • 인자 전달이 가능한 콜백 타입
  • VoidCallback
    typedef VoidCallback = void Function();
    • 인자가 없는 단순 콜백 타입

Facotory 생성자

  factory Block.fromJson(Map<String, dynamic> json) {
    if (json case {'type': String type, 'text': String text}) {
      return Block(type, text);
    } else {
      throw const FormatException('Unexpected JSON format');
    }
  }
  • 생성자의 호출 이름을 지정하는 네임드 생성자 역할
  • 실제 인스턴스를 만드는 로직을 포함하는 별도의 함수
    • 객체를 새로 만들 수도, 기존에 만들어진 객체를 반환할 수도, 아예 다른 클래스의 인스턴스를 반환할 수도 있음
  • static 함수 처럼 인스턴스 멤버를 직접 참조할 수 없음



나눗셈 연산 기호

  • ~/ : 정수 나눗셈 (int)
  • / : 나눗셈 (double)



sealed class

  sealed class Block {
      Block();}

  class HeaderBlock extends Block {
      HeaderBlock();
  }
  • 클래스 수정자
  • 같은 파일 내에서만 상속 가능



암시적 애니메이션

  • 전체 애니메이션을 자동으로 실행하는 사전 빌드된 애니메이션 효과
  • 일부 타겟 value, duration만 정의
  • ImplicitlyAnimatedWidget 베이스로 미리 정의 된 애니메이션의 옵션 값(scale, curve, duration ..)만 정의하면 됨
  • ex) AnimatedSize, AnimatedScale, AnimatedPositioned



명시적 애니메이션

  • 사전 빌드 된 애니메이션 효과
  • 정의 된 Animation 객체 필요
  • Animation
    • 실행중이거나 중지된 애니메이션을 나타내는 클래스
    • Listenable의 서브클래스
    • 애니메이션 실행 중 상태가 변경되면 리스너에게 알림
    • transitionBuilder에 애니메이션 객체(Transition) 정의해야함
  • AnimationController
    • 애니메이션을 만들고 상태를 제어하는 방법
    • 애니메이션 효과를 정의하지 않고 메서드로 제어 가능
    • StatefulWidget 위젯 & Ticker 필요
  • ex) SizeTransition, ScaleTransition, PositionedTransition

+ Recent posts