Skip to content

Instantly share code, notes, and snippets.

@mbrandonw
Created December 2, 2023 15:01
Show Gist options
  • Save mbrandonw/db904f2ad544da594eecd8c56ce86212 to your computer and use it in GitHub Desktop.
Save mbrandonw/db904f2ad544da594eecd8c56ce86212 to your computer and use it in GitHub Desktop.
FB12969716
# FB12969716
// FB: `Form` and
//
// Paste this into a fresh SwiftUI project's ContentView.swift to see a bug with `Form` views with
// conditional child views that use `@State`.
//
// 1. Tap "Toggle" to show the child view with a new model
// 2. Tap "+" in the child view to increment the model's state from 0 to another number
// 3. Tap "Toggle" two times to hide the child and then show it again
//
// Note that the child view does not show "0", as expected with the newly assigned model, but
// instead shows the previous incremented count. The child view's `@State` is still holding onto the
// old stale model, _not_ the model that lives in the parent `ContentView`.
//
// Workarounds:
//
// * Don't use `Form`. If you swap `Form` out for a `VStack`, the child view uses the freshest
// model for state.
// * Drop the use of `@State`.
import SwiftUI
@Observable
class Model {
var count = 0
}
struct ContentView: View {
@State var model: Model?
var body: some View {
Form { // 👈 Change this to 'VStack' to fix the problem
Button("Toggle") {
model = model == nil ? Model() : nil
}
if let model = model {
ChildView(model: model)
}
}
}
}
struct ChildView: View {
@State var model: Model // 👈 Or remove '@State'
var body: some View {
HStack {
Text("\(model.count)")
Button("+") {
model.count += 1
}
}
}
}
#Preview {
ContentView()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment