los.adrian
los.adrian

Reputation: 538

How could be change children @State property value from parent view in SwiftUI?

Given this code:

import SwiftUI

struct ContentView: View {
    @State private var someView = DefaultView()
    var body: some View {
        VStack { someView }
            //.onAppear { someView.change() } //1. Color not changing from here, isDisplay remains false
    }
}

struct DefaultView: View {
    @State private var isDisplay = false

    func change() {
        isDisplay = true
        print("isDisplay = \(self.isDisplay)")
    }

    var body: some View {
        Text("Hello!")
            .foregroundColor(isDisplay ? .red : .blue)
            //.onAppear { change() } //2. Color and isDisplay property is changing from here well
    }
}

I'd like to call change func from parent view (ContentView 1.). That runs because the print is visible on the debug area, but there is no any changes, the isDisplay property does not change from false to true. Why does this work that way? How can I change the @state property from the parent class?

Edit: It could work:

struct DefaultView: View {
    public var isDisplay: Bool

    init() {
        isDisplay = false
    }

    mutating func change() {
        isDisplay = true
        print("isDisplay = \(self.isDisplay)")
    }

    var body: some View {
        Text("Hello!")
            .foregroundColor(isDisplay ? .red : .blue)
    }
}

Upvotes: 2

Views: 2246

Answers (2)

Dan O'Leary
Dan O'Leary

Reputation: 946

I would use @Binding to change the value of the property in your DefaultView from a parent view. Here is a brief example.

struct ContentView: View {
    @State private var changeColor = false

    var body: some View {
        VStack {
            Button {
                changeColor.toggle()
            } label: {
                Text("Toggle Button")
                    .padding()
                    .foregroundColor(.red)
            }

            DefaultView(isDisplay: $changeColor)
        }
    }

}

struct DefaultView: View {
    @Binding var isDisplay: Bool

    var body: some View {
        Text("Hello")
            .foregroundColor(isDisplay ? .red : .blue)
    }
}

Upvotes: 2

swiftPunk
swiftPunk

Reputation: 1

The way you showed your code in question is not the way SwiftUI works, you are thinking in UIKit and coding SwiftUI?

Once you fired a View there is no return to use the imbedded function or any thing! SwiftUI-View is more like a gun build you can not change the direction or other property of it, after render is done! in the other hand UIKit-View is more like Rocket, after firing you have control on it and you can change destination and more other things as well. So there is deference between them, make your build lighter as possible. Because your going firing lots and SwiftUI should handel them as much as easily as possible.
Here the right way:

struct ContentView: View {
    
    @State private var isDisplay: Bool = Bool()
    
    var body: some View {

        DefaultView(isDisplay: isDisplay)
        
        Button("update") { isDisplay.toggle() }.padding()
        
    }
}



struct DefaultView: View {
    
    let isDisplay: Bool

    var body: some View {
        
        Text("Hello!")
            .foregroundColor(isDisplay ? .red : .blue)
        
    }
    
}

Upvotes: 2

Related Questions