View

300x250

기존에 FutureBuilder를 사용해서 파이어베이스에서 불러오는 데이터에 대해 비동기적인 UI를 만들어본 적이 있었다. 근데, 지금 생각해보면 너무 대충 만들고, FutureBuilder가 하는 역할이 뭔지만 찍먹하고 넘어가버렸던 것 같다.

그때는 요렇게 데이터가 들어오는 중일 때에는 왼쪽처럼 표시하고, 데이터가 들어오고 나면 오른쪽처럼 정상적으로 숫자가 보여지도록 만들었었다.

 

요즘에 앱개발이 재미있기도 하고, 여러가지 UX를 고려한 앱을 만들어내고싶다는 욕심이 생기고 있어서 비동기 UI 부분도 조금씩 건드려보려고 하고 있다. 바로 위에 만든 것도 어떻게 보면 비동기를 건드린 것이기는 하지만, 좀 더 미적인 느낌이 필요하지 않나 라고 생각된다. ㅋㅋㅋ


현재 내가 진행하고 있는 프로젝트에서는 비동기로 받아오는 데이터의 경우 Future<Either<Failure, DataType>> 의 형식을 사용하고 있다. 즉, [ 비동기로 데이터를 받아옴 → 받아온 데이터가 유효할 수도, 유효하지 않을 수도 있음 ] 의 의미를 가지고 있다.

비동기로 받아와야 하는 값이 int 값이라면 아래의 방식으로 데이터를 가져와서 화면을 그려주는 방식으로 대충 FutureBuilder도 사용하지 않고 UI를 그려주고 있었다. 그리고 이게 UX 적으로 정말 꽝이라는걸 몇 번 느끼고 개선의 필요성을 체감하고 있다.

Future<Either<Failure, int>> 

// fetchData 함수로 비동기로 데이터 받아오고, 뒤에 로직을 다 처리한 이후 targetValue에 값 저장
int? targetValue = await fetchData(params)
                        // 데이터에 대해 Either을 까보기
                        .then((result) => result.fold(
                                        // 만약 Left이면
                                        (failure) => null, 
                                        // 만약 Right 이면
                                        (data) => data,
                        ));

if (targetValue == null) {
	return NoDataWidget();
} else {
	return ValidDataWidget();
}

그래서 FutureBuilder를 도입하려 했는데, 이게 단순히 Future 만 있는게 아니라 Either 까지 섞여있다보니, 어떻게 분기를 처리해야 할 지 좀 애매했다. ㅜㅜ 그래서 조금 고민해봤는데 모든 state에 대해 각자 위젯을 그려줄 필요가 없다는 생각이 들어서 그려야하는 위젯 상태들을 분류해봤다

 

우선 Future의 Connection State는 4가지가 있다.

  • none : 데이터 받아오기 시작 전
  • waiting : 데이터가 들어오기를 기다리는 중 (현재 들어온 데이터 없음)
  • active : 데이터가 들어오는 중 (현재 들어온 데이터 일부 있음)
  • done : 데이터가 모두 들어옴

그리고 Either<Failure, Data> 타입에는 2개의 State가 있다.

  • left - Failure : 데이터를 정상적으로 받아오지 못하였음
  • right - Data : 데이터를 정상적으로 받아옴

단순히 State의 조합만 생각해보면 8개의 상태에 대한 위젯을 그려줘야 하지만, 사용자 입장에서는 이런 상태들은 중요하지 않고, 3가지 케이스 [성공, 실패, 대기] 만 UI를 통해 보여주면 된다.

 

 

그래서 아래처럼 정리된 상태에 대해 분기를 하여 위젯을 그려주도록 FutureBuilder 를 작성하였다.

final Future<Either<Failure, UserDataEntity>> futureUserEntity;

@override
Widget build(BuildContext context) {
  return FutureBuilder(
    future: futureUserEntity,
    builder: (context, snapshot) {
      if (snapshot.connectionState != ConnectionState.done) {
      // 로딩중인 상태에 대한 위젯 그려주기
        return LoadingWidget();
      }

      if (snapshot.hasData && snapshot.data!.isRight()) {
      // 성공 상태 위젯 그려주기
      // Either의 특성상 isRight이 true 이더라도 값을 가져올 때에는 left 인 경우도 책임져야하기에
      // 더미 모델을 넣어주었음 (더미 모델이 들어가는 경우는 거의 없지 않을까?)
        final userModel = snapshot.data!.getOrElse((l) => UserDataEntity.dummyModel);

        return SuccessWidget();
      }
      
      // 실패 상태 위젯 그려주기
      return FailWidget();
    },
  );
}

요걸 실행한 결과는 요런 방식으로 나온다 🙂 아름다워라…

 

UI쪽 개발을 조금 더 해보다가, 만약에 아예 이렇게 분리를 해둔걸 유틸리티 위젯으로 만들 필요성을 느끼면 한 번 유틸 코드로 분리하는 것까지 진행해봐야겠다!!

사실 앱을 만들면서 Failure가 굳이 필요한가?? 라는 생각도 들고있다. 아직 유효하게 Failure를 사용해본 적이 없기도 하고, Data를 가져오지 못한 것 자체를 FutureBuilder에서 처리를 해줄 수 있지 않나? 라는 고민이 있다. 요 부분은 사실 내가 프로젝트에 적용한 부분은 아니기도 하고 프로젝트를 시작할 때 플러터를 처음 배우고 있는 상태였기에, 처음에 타입을 도입할 때 적극적으로 고민을 해보지는 못했었던 부분이다. 미래에 진행 중인 프로젝트를 조금씩 개선할 때 요것도 개선여부에 넣을지 고민을 해봐야할 것 같다.


샤라웃

https://api.flutter.dev/flutter/widgets/ConnectionState.html

http://www.incodom.kr/Flutter/FutureBuilder

320x100
Share Link
reply
반응형
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31