xyyx
xyyx

Reputation: 153

Why is my child SwiftUI view not updating?

I have a Swift ui view with a child witch gets values from a @State variable. When i update my @State variable the view rebuilds but the child stays the same.

struct ContentView: View {  
  @State var msg: String = ""  
  var body: some View {  
    VStack {  
      Button(action: {  
        self.msg = "Hallo World"  
      }, label: { Text("Say Hallo")})  

      ChildView(msg: msg).padding().background(Color.orange)  
      Text(msg).padding().background(Color.green)  
    }.frame(maxWidth: .infinity, maxHeight: .infinity)  
  }  
}  

struct ChildView: View {  
  @State var msg: String  

  var body: some View {  
    Text(msg)  
  }  
}  

Upvotes: 5

Views: 3007

Answers (2)

user3441734
user3441734

Reputation: 17534

import SwiftUI

struct ContentView: View {
  @State var msg: String = ""
  var body: some View {
    VStack {
      Button(action: {
        self.msg += "Hallo World "
      }, label: { Text("Say Hallo")})

      ChildView(msg: msg).padding().background(Color.orange)
      Text(msg).padding().background(Color.green)
    }.frame(maxWidth: .infinity, maxHeight: .infinity)
  }
}

struct ChildView: View {
  var msg: String

  var body: some View {
    Text(msg)
  }
}

You don't need any state property wrapper in your ChildView. Once msg changed, SwiftUI know, that every View depending on its value should be "reloaded".

In your example, you "fixed" it by wrapping initial value to its state property wrapper. SwiftUI will not reload it, because @State property wrapper means, the value is stored outside of the ChildView. @State property wrapper in not part of View state. It is the opposite, once the @State wrapped property change, SwiftUI will reevaluate View's body computed property. To "reset" @State property wrapped value, you need "recreate" it, which means the state property will be reset to its initial value too.

enter image description here

Upvotes: 7

Asperi
Asperi

Reputation: 257493

Use in it @Binding instead of @State. Modified complete snapshot provided below. Tested as-is & works with Xcode 11.2 / iOS 13.2.

struct ContentView: View {
  @State var msg: String = ""
  var body: some View {
    VStack {
      Button(action: {
        self.msg = "Hallo World"
      }, label: { Text("Say Hallo")})

      ChildView(msg: $msg).padding().background(Color.orange)
      Text(msg).padding().background(Color.green)
    }.frame(maxWidth: .infinity, maxHeight: .infinity)
  }
}

struct ChildView: View {
  @Binding var msg: String

  var body: some View {
    Text(msg)
  }
}

Upvotes: 1

Related Questions