Search code examples
swiftswiftui

SwiftUI pass data to subview


So I have read a lot about swiftUI and I am confused. I understand the @State and how it update the view behind the scenes. The thing I can't understand is why when I the subview in this example is automatically updated when the state changes in the top view/struct given the fact that on the subview the var subname is not a @State property. I would expect this not to be updated. Can someone enlighten me please?

import SwiftUI

struct SwiftUIView: View {
    @State private var name = "George"
    var body: some View {
        VStack{
            SubView(subName: name).foregroundColor(.red)
            Button(action: {
                self.name = "George2"
            }) {
                Text("Change view name")
            }
        }
    }
}

struct SubView: View {
    var subName:String
    var body: some View {
        Text(subName)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        SwiftUIView()
    }
}

PS. If I change the subview to

struct SubView: View {
    @State var subName:String
    var body: some View {
        Text(subName)
    }
}

it's not updated when I press the button.


Solution

  • var subName: String

    struct SubView: View {
        var subName: String
        // ...
    }
    

    In the above example you don't really have a state. When the subName property in the parent view changes, the whole SubView is redrawn and thus provided with a new value for the subName property. It's basically a constant (try changing it to let, you'll have the same result).

    @State var subName: String

    struct SubView: View {
        @State var subName: String
        // ...
    }
    

    Here you do have a @State property which is initialised once (the first time the SubView is created) and remains the same even when a view is redrawn. Whenever you change the subName variable in the parent view, in the SubView it will stay the same (it may be modified from within the SubView but will not change the parent's variable).

    @Binding var subName: String

    struct SubView: View {
        @Binding var subName: String
        // ...
    }
    

    If you have a @Binding property you can directly access the parent's @State variable. Whenever it's changed in the parent it's changed in the SubView (and the other way around) - that's why it's called binding.