Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing @State variable does not update the View in SwiftUI

Tags:

ios

swift

swiftui

I have a following View (took out irrelevant parts):

struct Chart : View {
    var xValues: [String]
    var yValues: [Double]
    @State private var showXValues: Bool = false

    var body = some View {
        ...
        if showXValues {
            ...
        } else {
            ...
        }
        ...
    }
}

then I wanted to add a way to modify this value from outside, so I added a function:

func showXValues(show: Bool) -> Chart {
    self.showXValues = show
    return self
}

so I build the Chart view from the outside like this:

Chart(xValues: ["a", "b", "c"], yValues: [1, 2, 3])
    .showXValues(true)

but it works as if the value was still false. What am I doing wrong? I thought updating an @State variable should update the view. I am pretty new to Swift in general, more so to SwiftUI, am I missing some kind of special technique that should be used here?

like image 933
iSpain17 Avatar asked Dec 17 '19 20:12

iSpain17


People also ask

How do I refresh a view in SwiftUI?

To add the pull to refresh functionality to our SwiftUI List, simply use the . refreshable modifier. List(emojiSet, id: \. self) { emoji in Text(emoji) } .

What does @state do in SwiftUI?

With @State, you tell SwiftUI that a view is now dependent on some state. If the state changes, so should the User Interface. It's a core principle of SwiftUI: data drives the UI.


2 Answers

As in the comments mentioned, @Binding is the way to go.

Here is a minimal example that shows the concept with your code:

struct Chart : View {
    var xValues: [String]
    var yValues: [Double]
    @Binding var showXValues: Bool

    var body: some View {
        if self.showXValues {
            return Text("Showing X Values")
        } else {
            return Text("Hiding X Values")
        }
    }
}

struct ContentView: View {
    @State var showXValues: Bool = false

    var body: some View {
        VStack {
            Chart(xValues: ["a", "b", "c"], yValues: [1, 2, 3], showXValues: self.$showXValues)
            Button(action: {
                self.showXValues.toggle()
            }, label: {
                if self.showXValues {
                    Text("Hide X Values")
                }else {
                    Text("Show X Values")
                }
            })
        }
    }
}
like image 82
Unpunny Avatar answered Oct 01 '22 15:10

Unpunny


Okay, answer is pretty dumb.

There is no need to create func-s. All I have to do is not mark the properties as private but give them an initial value, so they're gonna become optional in the constructor. So user can either specify them, or not care. Like this:

var showXLabels: Bool = false

This way the constructor is either Chart(xLabels:yLabels) or Chart(xLabels:yLabels:showXLabels).

Question had nothing to do with @State.

like image 26
iSpain17 Avatar answered Oct 01 '22 15:10

iSpain17