반응형
SwiftUI에서 많이 하는 실수 - onChange(of:)를 잘못 사용해 과도한 리렌더링이 일어나는 실수
onChange(of:)는 특정 값이 변할 때마다 콜백을 실행하는 유용한 도구입니다.
하지만 매 타이핑마다, 스크롤마다, 작은 변화마다 무거운 작업을 수행하면
성능 문제가 바로 드러납니다.
1. 문제 원인
- 텍스트 필드 입력 값이 바뀔 때마다 네트워크 검색 API 호출
- onChange 안에서 곧바로 정렬/필터/디스크 쓰기 등의 무거운 작업 수행
- debounce/throttle 개념 없이 모든 변화를 1:1로 처리
2. 나타나는 증상
- 검색창에 글자를 빨리 입력하면 앱이 버벅거림
- 서버에 불필요하게 많은 검색 요청이 날아감
- onChange 내부에서 상태를 또 바꾸다가 무한 루프/복잡한 흐름 발생
3. 잘못된 코드 예시
struct SearchView: View {
@State private var query: String = ""
@StateObject private var viewModel = SearchViewModel()
var body: some View {
VStack {
TextField("검색", text: $query)
.textFieldStyle(.roundedBorder)
.onChange(of: query) { newValue in
// ❌ 타이핑마다 API 호출
Task {
await viewModel.search(keyword: newValue)
}
}
List(viewModel.results, id: \.id) { result in
Text(result.title)
}
}
}
}
4. 올바른 코드 예시 (debounce 적용)
4-1. 간단한 debounce 구현
@MainActor
final class SearchViewModel: ObservableObject {
@Published var results: [SearchResult] = []
private var searchTask: Task<Void, Never>?
func searchDebounced(keyword: String) {
searchTask?.cancel()
searchTask = Task {
try? await Task.sleep(nanoseconds: 300_000_000) // 0.3초
guard !Task.isCancelled else { return }
await search(keyword: keyword)
}
}
func search(keyword: String) async {
// 실제 검색 API 호출
}
}
4-2. View에서 사용
struct SearchView: View {
@State private var query: String = ""
@StateObject private var viewModel = SearchViewModel()
var body: some View {
VStack {
TextField("검색", text: $query)
.textFieldStyle(.roundedBorder)
.onChange(of: query) { newValue in
viewModel.searchDebounced(keyword: newValue)
}
List(viewModel.results, id: \.id) { result in
Text(result.title)
}
}
}
}
5. 정리 및 팁
- onChange는 “변화가 자주 일어나는 값”에 연결할수록,
내부에서 수행하는 작업을 더 가볍게 유지해야 합니다. - 네트워크 호출/디스크 쓰기/무거운 필터링 등이 포함된다면
debounce/throttle 같은 완충 장치를 두는 것을 기본으로 생각해야 합니다.
반응형
'Dev Study > SwiftUI' 카테고리의 다른 글
| SwiftUI에서 많이 하는 실수 - View 중첩이 지나치게 깊어져 가독성과 유지보수가 나빠지는 실수 (0) | 2025.12.05 |
|---|---|
| SwiftUI에서 많이 하는 실수 - Modifier 순서를 이해하지 못해 스타일이 적용되지 않는 실수 (0) | 2025.12.05 |
| SwiftUI에서 많이 하는 실수 - 도메인 모델과 UI 전용 모델을 구분하지 않는 실수 (0) | 2025.12.05 |
| SwiftUI에서 많이 하는 실수 - Preview에서 실제와 다른 상태를 구성해 놓고 디버깅이 꼬이는 실수 (0) | 2025.12.05 |
| SwiftUI에서 많이 하는 실수 - animation()을 남발해 의도치 않은 애니메이션이 발생하는 실수 (0) | 2025.12.05 |
| SwiftUI에서 많이 하는 실수 - List 셀 내부에서 상태 변경/로직을 수행해 무한 렌더링이 발생하는 실수 (0) | 2025.12.05 |
| SwiftUI에서 많이 하는 실수 - ScrollView 안에서 LazyVStack을 사용하지 않아 성능이 나빠지는 실수 (0) | 2025.12.05 |
| SwiftUI에서 많이 하는 실수 - offset을 레이아웃 도구로 사용해서 반응형이 깨지는 실수 (0) | 2025.12.05 |

