I'm using the refreshable modifier on List
https://developer.apple.com/documentation/SwiftUI/View/refreshable(action:)
The List is contained in a view (TestChildView) that has a parameter. When the parameter changes, TestChildView is reinstantiated with the new value. The list has a refreshable action. However, when pulling down to refresh the list, the refresh action is run against the original view instance, so it doesn't see the current value of the parameter.
To reproduce with the following code: If you click the increment button a few times, you can see the updated value propagating to the list item labels. However, if you pull down the list to refresh, it prints the original value of the parameter.
I assume this is happening because of how refreshable works .. it sets the refresh environment value, and I guess it doesn't get updated as new instances of the view are created.
It seems like a bug, but I'm looking for a way to work around -- how can the refreshable action see the current variable/state values?
import SwiftUI
struct TestParentView: View {
@State var myVar = 0
var body: some View {
VStack {
Text("increment")
.onTapGesture {
myVar += 1
}
TestChildView(myVar: myVar)
}
}
}
struct TestChildView: View {
let myVar: Int
struct Item: Identifiable {
var id: String {
return val
}
let val: String
}
var list: [Item] {
return [Item(val: "a \(myVar)"), Item(val: "b \(myVar)"), Item(val: "c \(myVar)")]
}
var body: some View {
VStack {
List(list) { elem in
Text(elem.val)
}.refreshable {
print("myVar: \(myVar)")
}
}
}
}
The value of
myVarinTestChildViewis not updated because it has to be a@Binding. Otherwise, a new view is recreated.If you pass the value
@State var myVarfromTestParentViewto a@Binding var myVartoTestChildView, you will have the value being updated and the view kept alive the time of the parent view.You will then notice that the printed value in your console is the refreshed one of the
TestChildView.Here is the updated code (See comments on the updated part).