티스토리 뷰

SwiftUI에서 코드를 짜다가 정말 예상치도 못한 일이 발생했다.

자식 뷰에서 State를 초기화할 때, 데이터를 확인하기 위해서 print()를 포함시켰다.

그리고 부모 뷰가 리빌드될 때마다, 자식 뷰의 State가 초기화가 되면서 print()가 출력되는 것이였다.

 

대략적인 코드는 다음과 같다.

import SwiftUI

struct ContentView: View {
    @State private var text: String = ""
    var body: some View {
        NavigationStack {
            TextField(text: $text, label: {
                Text("TextField")
            })
            NavigationLink(destination: {
                ChildView1()
            }, label: {
                Text("ChildView")
            })
        }
    }
}

struct ChildView1: View {
    @State private var num: Int = {
        print("Child View 1 state")
        return 0
    }()
    
    var body: some View {
        ChildView2()
            .onAppear {
                print("Child View 1 onAppear")
            }
    }
}

 

나는 이 사건이 발생하기 전까지 NavigationLink의 destination은 네비게이션 이동 시 실행되는 줄 알았다.

=> 아니다. destination의 뷰도 body 호출시 포함된다.

 

그리고 State는 뷰에 포함될 때, 한번만 초기화되는 줄 알았다.

=> 아니다. 리빌드될 때마다, 즉 body가 호출될 때마다, body에 포함되는 자식 뷰들의 모든 State가 초기화가 된다.

 

위의 코드에서 TextField의 text가 변할 때마다, 바인딩된 text 상태는 변하게 될 것이다. 그러면 text 상태가 바뀔 때마다 ContentView는 리빌드가 되기 때문에 body가 호출된다. 

그리고 body가 호출될 때마다 body에 포함된 자식 뷰들도 새로 만들어지게 된다. 

 

자식 뷰들이 새로 만들어 지면 어떻게 될까?

State가 새로 만들어지게 된다!

( 이것을 꼭 기억하자! )

 

따라서 위의 코드는 ContentView가 리빌드될 때마다 ChildView1의 State가 초기화되고, "Child View 1 state"가 출력되게 된다.

하지만 "Child View 1 onAppear"는 ChildView1가 화면에 보일 때, 한번만 출력되게 된다.

 

꼭 기억하자!

1. NavigationLink의 destination의 뷰가 보이지 않아도 자식 뷰로 포함된다.

2. 부모 뷰가 리빌드되면, 모든 자식 뷰가 새로 만들어진다.

3. 매개변수로 State를 초기화한다면 onAppear 수정자에서 초기화를 하자.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/09   »
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
글 보관함