View
기존에 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
'Develop > Flutter 개발' 카테고리의 다른 글
[Flutter] Firebase에서 닉네임 문자열 필드에 대한 검색(인 척 하는) Query 기능 구현 (0) | 2024.05.22 |
---|---|
[Flutter] map 함수는 단순히 리스트를 순회하는 함수가 아니다 (0) | 2024.05.18 |
[Flutter] 이미지 에셋을 로딩할 때는 FutureBuilder 보다 Image의 loadingBuilder를 쓰자 (0) | 2024.03.03 |
[Flutter] Scroll 시 AppBar가 반투명하게 아래쪽 Content를 비치는 경우 제거하기 (0) | 2024.03.02 |
[Flutter] fullscreen dialog에서 push replacement는 안된다 (0) | 2024.02.22 |