I'm trying to create a SwiftUI app, and I'm encountering some surprising behavior. I have a background in React.js so I'm familiar with declarative UI systems, but I think that's working against me here because this isn't behaving as I would expect.
So what I'm trying to do with this code is create a button that changes some state values and causes a sheet to open from the bottom of the page and display a value.
struct ExampleView: View {
@State var pageOpen: Bool = false
@State var valueString: String = "Initial Value (you shouldn't see this)"
var body: some View {
NavigationView {
Button(action: {
valueString = "Testing"
pageOpen = true
}) {
Text("Click me")
}
}
.sheet(isPresented: $pageOpen) {
let _ = print("pageOpen is \(pageOpen)")
let _ = print("valueString is \(valueString)")
Text(valueString)
}
}
}
This works the second or third time I run open the sheet, but the first time I click the button, it's like the variables haven't been updated yet. The values printed are still the initial values.
I could reiterate how I think this should work but clearly I'm misunderstanding something.
Edit: I'm using XCode 13, testing in the iOS 15 simulator.
Definitely weird. Try maybe adding .onChange(of: pageOpen) { print($0) } and .onChange(of: valueString) { print($0) } to the NavigationView, and see if it prints as expected there.
Usually in SwiftUI we try and not put any side effects in a ViewBuilder (which is what that .sheet modifier expects there) because it can do some weird things. We instead use specific tools like .onAppear {}, .task {} or here .onChange to perform these kind of small side effects.
1 Like
Adding .onChange(of: valueString) {_ in} to the navigation view fixes the problem, and the correct string is displayed on the screen.
I also sent a link to this question to a friend. He speculates that "it doesn’t know to refresh the view because you don’t have a dependency on valueString in the navigation view." So adding this dependency, in the form of a .onChange(of: valueString) causes everything to refresh.
I'm still not confidant enough to say that this is a bug; maybe there's a better solution. But for now I'm going to use this work-around.
Thank you very much for confirming that my understanding isn't totally flawed.
1 Like