
Flow를 사용하다 보면 방출된 값을 다른 Flow 데이터로 변환해야 하는 경우가 있다.
최근 Compose 프로젝트를 진행하면서 Paging3 라이브러리 사용없이 페이징을 구현했던 경험이 자주 있었다.
페이징 기능을 구현하며 사용한 .flatMapConcat()에 대해 소개해보려 한다.

위 사진은 코틀린 공식문서에 나와있는 내용이다.
원본 Flow가 방출하는 원소들을 변환하여 새로운 Flow를 생성하고, 이 Flow들을 연결하고 평탄화합니다.
이 메서드는
map(transform).flattenConcat()의 단축 형태입니다.flattenConcat을 참조하십시오.비록 이 연산자가 매우 친숙해 보일지라도, 정규 애플리케이션 특화 Flow에서 사용하는 것을 권장하지 않습니다. 대부분의 경우, map 연산자에서 서스펜딩 작업을 수행하는 것이 충분하며, 선형 변환이 훨씬 이해하기 쉽습니다.
요약하자면 Flow가 값을 방출하게되면 새로운 Flow 데이터로 값을 반환해준다.
요구 사항
- 사용자가 스크롤을 할때 아이템이 특정 임계값 이상 스크롤 되면 Pagenation을 진행한다.
- Pagenation 할 때 갤러리로부터 사진들을 가져온다.
- 가져온 사진들을 기존 리스트와 합쳐 상태를 업데이트 한다.

사용자가 스크롤하여 Pagenation을 하려 할 때 UI 단에서의 처리는 SideEffect로 분류하여 LaunchedEffect 블럭 내부에서 fetchNextGalleryList() 함수를 호출해주고 있다.
page가 업데이트 됨에 따라 init 내부에 선언된 ViewModelScope 블럭안에서 getGalleryImagesUseCase()의 반환값을 수집하여 uiState를 업데이트 해주고 있다.

UseCase의 코드를 확인해보면 Flow<List<ImageInfo>>라는 Flow 를 반환해주고 있는데 _page를 .flatMapConcat() 해주면 해당 블럭 내부에서 _page value를 사용하며 내부에서 새로운 Flow 데이터를 반환할 수 있다.
마지막으로 새로운 Flow 데이터를 수집하여 List<ImageInfo> 값을 사용할 수 있는것이다.
그렇다면 Flow를 다른 Flow로 변환하기 위한 방법중 .flatMapLatest() 라는 연산자도 있는데 .flatMpaConcat()과 차이가 무엇일까?

Flow가 값을 방출할 때마다
transform함수에 의해 새로운 Flow를 반환합니다.
기존의 Flow가 새 값을 방출하면transform블록에 의해 생성된 이전 Flow는 취소됩니다.이 연산자는 기본적으로 버퍼링되며, 출력 버퍼는 후속 버퍼 연산자를 적용하여 변경할 수 있습니다.
.flatMapLatest()의 가장 큰 특징은 '이전 Flow가 취소 될 수 있다.' 라는 점이다.
예시 코드처럼 만일 .flatMapConcat()으로 대신 사용하였을 경우 결과값은 a a_last b b_last라는 값을 획득할 수 있을 것이다.
하지만 .flatMapLatest()는 작업이 지속되고 있을 때, 하위 Flow의 작업이 상위 Flow의 작업보다 늦어질 경우 이전에 방출된 데이터로 인한 작업은 취소되고 이후 발생한 데이터로 작업을 진행할 수 있다.
요구사항인 '갤러리로부터 모든 이미지 리스트를 불러와야 하는 것'은 속도와 관계없이 안전하게 데이터들을 불러와야 하는것이기에
.flatMapLatest()연산자보다.flatMapConcat()연산자가 적합하다.