Home > Mobile >  Updating a @State var Double from a struct array in SwiftUI
Updating a @State var Double from a struct array in SwiftUI

Time:03-31

I have been looking on StackOverFlow (and on Internet) the entire day to make this button works but I haven't found anything.

As you can see, I want to change the value when I click on the button by using the simplest solution possible.

Here are the codes :

// Element.swift

import Foundation
import SwiftUI

struct Element: Identifiable {
    let id = UUID()
    @State var value: Double
    let title: String
}

let elements = [
    Element(value: 10, title: "This is a title"),
    Element(value: 100, title: "This is another title")
]
// ElementView.swift

import SwiftUI

struct ElementView: View {

    let element: Element

    var body: some View {
        HStack {
            Text(element.title)
            Text("\(element.value)")
            Button("More", action: { element.value  = 10 })
        }
    }

}

struct ElementView_Previews: PreviewProvider {
    static var previews: some View {
        ElementView(element: elements[0])
    }
}
// ContentView.swift

import SwiftUI

struct ContentView: View {

    var body: some View {
        VStack {
            ForEach(elements) { element in
                ElementView(element: element)
            }
        }
    }

}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Surprisingly, I don't have any issue with Xcode.

What did I miss? Thanks in advance! :P

CodePudding user response:

You have a couple of issues with how you're treating state. In general, in SwiftUI, state is held by a parent and passed down to a child via Binding. It's also very important that @State is for use inside a View -- not inside your model.

See inline comments for changes and explanations.

struct Element: Identifiable {
    let id = UUID()
    var value: Double //Remove @State here -- @State is for use in a View
    let title: String
}

struct ElementView: View {

    @Binding var element: Element //pass Element via Binding so it is mutable

    var body: some View {
        HStack {
            Text(element.title)
            Text("\(element.value)")
            Button("More", action: { element.value  = 10 })
        }
    }

}

struct ElementView_Previews: PreviewProvider {
    static var previews: some View {
        ElementView(element: .constant(Element(value: 10, title: "This is a title"))) //use .constant() for a Binding in a Preview
    }
}

struct ContentView: View {
    @State private var elements = [ //define elements with @State so they are mutable
        Element(value: 10, title: "This is a title"),
        Element(value: 100, title: "This is another title")
    ]
    
    var body: some View {
        VStack {
            ForEach($elements) { $element in //use element binding syntax to get a binding to each item in the array
                ElementView(element: $element)
            }
        }
    }

}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
  • Related