MOBILE

[flutter] BlocSelector

2023. 11. 17. 09:41
목차
  1. 1. 스크린에서 보여주어야 할 위젯 작성.
  2. 2. Bloc에서 API 통신 이후 state 변경 
  3. 3. 변경된 state를 BlocSelector 가 감지하고 위젯을 다시 빌드한다. 
  4. 그래도 state의 감지가 어렵다면,
728x90
반응형

 

 

사이드로 시작한 프로젝트에서 사용한 blocSelector 를 정리한다. 

 

일반적으로 블록 패턴을 사용할때에는 BlocBuilder / BlocListener / BlocSelector 등을 많이 사용하는 것 같다.

 

그중 특정 State의 특정 값을 감지해서 위젯을 리빌드하는 블록 셀렉터를 기록한다. 

 

 

전체 코드는 다음에서 확인 가능하다.

 

https://github.com/jaemanc/freight_front

 

GitHub - jaemanc/freight_front

Contribute to jaemanc/freight_front development by creating an account on GitHub.

github.com

 

 

BlocListener는 인자로 Bloc과 State를 받는다. 

 

BlocListener<BlocType, StateType>(
  bloc: myBloc,
  listener: (BuildContext context, StateType state) {
    // 상태 변화에 대한 리스너 작성
    // state에는 현재의 bloc 상태가 전달됩니다.
  },
  child: YourWidget(),
);

 

 

반면 BlocSelector는 State의 특정 값만 선택해서 감지한다. 

 

BlocSelector<BlocType, StateType, SelectedType>(
  selector: (StateType state) {
    // 선택적으로 추출하고자 하는 부분의 데이터를 리턴
    return state.selectedData;
  },
  builder: (BuildContext context, SelectedType selectedData) {
    // 추출된 데이터를 사용하여 화면을 업데이트
    return YourWidget(selectedData: selectedData);
  },
);

 

 

자주 변경되는 상태라면 BlocListener에 비해 위젯 빌드의 횟수를 줄일 수 있고, 불필요한 리렌더링을 줄여 줄 수 있다는 장점이 있다. 

 

 

 

1. 스크린에서 보여주어야 할 위젯 작성.

 

 

 

 

2. Bloc에서 API 통신 이후 state 변경 

 

 

  AuthenticationBloc(this._authenticationRepository)
:   super(InitAuthenticationBloc()) {
  on<Login>(_login);
  on<Registration>(_registration);
  on<Refresh>(_refresh);
  on<GuestLoginEvent>(_guestLoginEvent);
  }

 

이벤트를 통해 블록에서 API를 호출한다. 

 

 

enum AuthenticationStateStatus { initial, loading, loadSuccess, loadFailure }

 

state는 loadSuccess 로 변경해준다. 

 

 

3. 변경된 state를 BlocSelector 가 감지하고 위젯을 다시 빌드한다. 

 

글은 편하게 썼지만 state의 불변성, 감지하는 객체의 어느 부분을 바꿔야 하는 지 확인하는 과정에서 삽질을 많이 했다.

 

 

핵심은 변경해야 하는 State의 불변성을 유지해 주는 것.

 

 

따라서 final 로 작성한다. 

 

 

 

그래도 state의 감지가 어렵다면,

BlocObserver를 사용하는 것이 유용하다. 

 

BlocObserver를 사용 할 경우, 블록을 통한 상태 변화를 감지해준다. 

 

 

 

main에서 

 

observer를 세팅만 해주면 감지해준다. 

 

 

 

 

사인업 페이지에서는 initial status를 감지했다. 

 

 

 

 

 

 

 

입력하고 회원가입을 처리하면,

 

 

 

 

로그인 성공 위젯을 빌드하고, state의 상태도 loadSuccess로 변경된것을 감지한 로그가 프린트된다. 

 

 

 

 

 

 

다음은 스크린 코드이다. 

 

class _SignUpFormState extends State<SignUpForm> {
  AuthenticationBloc get authenticationbloc =>
      context.read<AuthenticationBloc>();

  final _formKey = GlobalKey<FormState>();
  String? _id;
  String? _contact;
  String? _email;
  String? _name;

  @override
  Widget build(BuildContext context) {
    double screenHeight = MediaQuery.of(context).size.height;
    double screenWidth = MediaQuery.of(context).size.width;

    return BlocSelector<AuthenticationBloc, AuthenticationState, AuthenticationStateStatus>(
        selector: (state) {
          logger.i(' ${state} ');
          return state.status;
        }, builder: ((context, state) {
        logger.i(' ${state}');
        return state != AuthenticationStateStatus.loadSuccess
          ? Column(children: <Widget>[
            Row(children: [_exitBtn()]),
            Align(
                alignment: Alignment.center,
                child: Form(
                    key: _formKey,
                    child: Column(
                      children: <Widget>[ 
                        Container(
                          margin: EdgeInsets.only(
                              top: screenHeight * 0.1,
                              bottom: screenHeight * 0.1),
                          child: const Image(image: AppImages.mainTruck),
                        ),
                        SizedBox(
                          width: screenWidth * 0.5,
                          child: Column(
                            children: [
                              TextFormField(
                                decoration: InputDecoration(labelText: 'ID'),
                                validator: (value) {
                                  if (value == null || value == '') {
                                    return 'ID를 입력해주세요.';
                                  }
                                  return null;
                                },
                                onSaved: (value) {
                                  _id = value;
                                },
                              ),
                              TextFormField(
                                decoration:
                                    InputDecoration(labelText: 'Contact'),
                                validator: (value) {
                                  if (value == null || value == '') {
                                    return 'Contact를 입력해주세요.';
                                  }
                                  return null;
                                },
                                onSaved: (value) {
                                  _contact = value;
                                },
                              ),
                              TextFormField(
                                decoration:
                                    InputDecoration(labelText: 'E-mail'),
                                validator: (value) {
                                  if (value == null || value == '') {
                                    return 'E-mail을 입력해주세요.';
                                  }
                                  return null;
                                },
                                onSaved: (value) {
                                  _email = value;
                                },
                              ),
                              TextFormField(
                                decoration:
                                    InputDecoration(labelText: 'Name'),
                                validator: (value) {
                                  if (value == null || value == '') {
                                    return '이름을 입력해주세요.';
                                  }
                                  return null;
                                },
                                onSaved: (value) {
                                  _name = value;
                                },
                              ),
                            ],
                          ),
                        ),
                        SizedBox(height: 16),

                        ElevatedButton(
                          onPressed: () => {
                            if (_formKey.currentState!.validate())
                              {
                                _formKey.currentState!.save(),
                                // call SignUp API
                                authenticationbloc.add(Registration(
                                    UserEntity(
                                        userId: _id,
                                        contact: _contact,
                                        email: _email,
                                        name: _name,
                                        isLogin: false))),
                              }
                          },
                          child: Text('Sign Up!'),
                        ),
                        SizedBox(height: 16),
                        ElevatedButton(
                            onPressed: () => {
                                  authenticationbloc.add(GuestLoginEvent()),
                                  setState(() {
                                    AuthenticationStateStatus.loadSuccess;
                                  })
                                },
                            child: Text('Guest'))
                      ],
                    ))),
          ]) : Text('로그인 성공했습니다!');
              
        }));
  }

 

320x100
반응형
저작자표시 (새창열림)

'MOBILE' 카테고리의 다른 글

[ERROR] flutter sdk null safety  (0) 2023.09.21
[ERROR] / No apps connected. sendng "reload" to all React ...  (0) 2022.06.26
react native expo 환경 설정  (0) 2022.02.01
  1. 1. 스크린에서 보여주어야 할 위젯 작성.
  2. 2. Bloc에서 API 통신 이후 state 변경 
  3. 3. 변경된 state를 BlocSelector 가 감지하고 위젯을 다시 빌드한다. 
  4. 그래도 state의 감지가 어렵다면,
'MOBILE' 카테고리의 다른 글
  • [ERROR] flutter sdk null safety
  • [ERROR] / No apps connected. sendng "reload" to all React ...
  • react native expo 환경 설정
girin_dev
girin_dev
기록합시다.
250x250
girin_dev
girin_dev
girin_dev

github.com/jaemanc


전체
오늘
어제
  • 분류 전체보기 (122)
    • ALGORITHM (23)
    • AWS (4)
    • Effective Java (4)
    • ERROR (12)
    • DB (11)
    • JAVA (23)
      • SPRING (10)
    • PYTHON (5)
      • TOY_PROJECT (1)
    • MOBILE (4)
    • SERVER (8)
    • TIPS (16)
    • WAS (2)
    • 새싹 일기 (5)
    • DATA (2)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • docker
  • spring boot
  • vertica
  • react-native
  • oracle
  • error
  • 새싹
  • Chat GPT
  • 다이나믹 프로그래밍
  • JAVA 11
  • oracle cloud
  • querydsl
  • Effective Java
  • jwt
  • 바질 키우기
  • 바둑이
  • 프로그래머스
  • springboot
  • 바질 페스토
  • IntelliJ
  • 바질
  • offset
  • Flutter
  • python3
  • dp
  • java
  • 가장 큰 수
  • centos7
  • lis
  • CentOS 8

최근 댓글

최근 글

hELLO · Designed By 정상우.
girin_dev
[flutter] BlocSelector
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.