나의 발자취

[SwiftUI ver] 당근마켓 거래서비스 풀스택 구현하기 (Frontend) - 무한 스크롤 본문

앱 개발/iOS

[SwiftUI ver] 당근마켓 거래서비스 풀스택 구현하기 (Frontend) - 무한 스크롤

달모드 2024. 11. 19. 12:09

2024.11.15 - [앱 개발/iOS] - [SwiftUI ver] 당근마켓 거래서비스 풀스택 구현하기 (Frontend) - 로그인, 회원가입, 상품 리스트 업데이트

 

[SwiftUI ver] 당근마켓 거래서비스 풀스택 구현하기 (Frontend) - 로그인, 회원가입, 상품 리스트 업데

2024.11.15 - [Backend] - [SwiftUI ver] 당근마켓 거래서비스 풀스택 구현하기 (Backend) [SwiftUI ver] 당근마켓 거래서비스 풀스택 구현하기 (Backend)달라진 것- 에러핸들링: 에러코드별로 에러 내역을 불러준

wildguess.tistory.com

 

지난 포스팅에 이어서 무한스크롤을 이어서 구현한다.


오류 나는 이유: environment object를 가져와야하는데 없어서 그렇다.

ContentView에 넣어놨기 때문에, 실제 돌리면 문제가 안생기는데 미리보기에서는 문제가 생긴다.

 

그러면 아래와 같이 정상적으로 가져올 수 있게 된다.

 

무한 스크롤

제일 마지막 항목이 읽혔을 때 더 읽어서 가져와야하기 때문에, ScrollView와 lazy VStack을 사용한다.

우리는 지금 리스트를 못쓰기 때문에 순회를 위해 lazy VStack의 forEach를 사용할것이다.

 

SaleListView.swift

의 List() 아래에 이어서 ScrollView를 만들어준다.

 

ForEach를 보면, 여러 생성자들 중에서 Identifiable를 적용한 것들이 성능이 빠르므로 선택

 

 

그리고 두 번째 생성자는 identifiable 한 것이 오므로, Model.swift에 가서 saleVM.sales를 하나 꺼냈을 때 하나가 뭐인지 보고 온다 -> sale

 

이므로 참고해서 적어준다.

그리고 아래와 같이 나타나는걸 확인해준 후 List()는 지워주기로 한다.

 

onAppear {} 를 추가해서 추가 데이터를 끌어와준다.

 

마지막으로, 위에서 설명한 대로 항목의 제일 마지막 항목이랑 비교를 해주고 onAppear에다 업데이트를 해준다.

 

여기서 if sale == saleVM.sales.last { 를 주목.

지금 ForEach로 가져오는 sale 과, saleVM.sales.last를 비교하려면, 루프 안 sale 변수로 가지고 오는 모델이 Equatable 프로토콜을 따라야한다. 

 

 

최종 코드

import SwiftUI

struct SaleListView: View {
    @EnvironmentObject var saleVM: SaleViewModel
    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(saleVM.sales) { sale in
                    SaleRowView(sale: sale).onAppear {
                        if sale == saleVM.sales.last {
                            saleVM.fetchSales()
                        }

                    }
                }
            }.onAppear{
                saleVM.fetchSales()
            }
        }
    }
}

#Preview {
    let saleVM = SaleViewModel()
    SaleListView().environmentObject(saleVM)
}

 

 


ScrollView를 Embed in...으로 해주고 NavigationSplitView로 감싸준다. 짝인 detail: 도 설정해주고,

 

이제 NavigationLink{}로도 감싸줘야한다. 짝인 label: 에다가는 원래의 ForEach() 뒤 클로저 내용을 붙여넣고, NavigationLink{}에는 일단 SaleRowView(sale: sale) 을 임시로 넣어준다.

 

 

그리고 나서 네비게이션 타이틀이나 버튼을 달아준다.

최종 코드

   
    var body: some View {
        NavigationSplitView {
            ScrollView {
                LazyVStack {
                    ForEach(saleVM.sales) { sale in
                        NavigationLink {
                            SaleRowView(sale: sale)
                        } label: {
                            SaleRowView(sale: sale)
                                .onAppear {
                                    if sale == saleVM.sales.last {
                                        saleVM.fetchSales()
                                    }
                                }
                        }
                    }
                    .padding(.horizontal)
                }
                .onAppear {
                    saleVM.fetchSales()
                }
            }
            .navigationTitle("판매목록")
            .navigationBarTitleDisplayMode(.large)
            .alert("상품목록", isPresented: $saleVM.isFetchError) {
                Button("확인", role: .cancel) {}
            } message: {
                Text(saleVM.message)
            }
        } detail: {
            Text("판매 세부정보를 선택하세요")
        }
    }
}
Comments