Reputation: 10330
I have TabView
containing 2 entries....both trigger display of StationListView
. The issue I have is that when I click on 2nd tab, the onAppear
is being called twice (once each for the 2 instances) having the effect of data for 2nd tab showing, following shortly by data again for 1st tab.
struct ContentView : View {
@ObservedObject var cityBikesViewModel = CityBikesViewModel(repository: CityBikesRepository())
@State private var selection = 0
var body: some View {
TabView(selection: $selection) {
StationListView(cityBikesViewModel: cityBikesViewModel, network: "galway")
.tabItem {
VStack {
Image(systemName: "location")
Text("Galway")
}
}.tag(0)
StationListView(cityBikesViewModel: cityBikesViewModel, network: "oslo-bysykkel")
.tabItem {
VStack {
Image(systemName: "location")
Text("Oslo")
}
}.tag(1)
}
}
}
struct StationListView: View {
@ObservedObject var cityBikesViewModel : CityBikesViewModel
var network: String
var body: some View {
NavigationView {
List(cityBikesViewModel.stationList, id: \.id) { station in
StationView(station: station)
}
.navigationBarTitle(Text("Bike Share"))
.onAppear(perform: {
self.cityBikesViewModel.fetch(network: self.network)
})
}
}
}
Full code at https://github.com/joreilly/BikeShare/blob/master/ios/BikeShare/BikeShare/ContentView.swift
Upvotes: 0
Views: 371
Reputation: 154533
You'd like the view to reload the data from the network when it is selected. Unfortunately, .onAppear
doesn't work because the View isn't loaded when you select it.
Instead, reload the data when selection
changes.
To make this work in SwiftUI 2.0 (Xcode 12), pass the tag
number and selection
(as a Binding
) to the StationListView
, then have StationListView
reload the data when the tag
matches the selection
both .onAppear
and when selection
changes using onChange(of: selection)
:
struct StationListView: View {
@ObservedObject var cityBikesViewModel : CityBikesViewModel
var network: String
var tag: Int
@Binding var selection: Int
var body: some View {
NavigationView {
List(cityBikesViewModel.stationList, id: \.id) { station in
StationView(station: station)
}
.navigationBarTitle(Text("Bike Share"))
.onChange(of: selection) { _ in
refreshData()
}
.onAppear {
refreshData()
}
}
}
func refreshData() {
if tag == selection {
cityBikesViewModel.fetch(network: self.network)
}
}
}
Here is the TabView
:
TabView(selection: $selection) {
StationListView(cityBikesViewModel: cityBikesViewModel, network: "galway", tag: 0, selection: $selection)
.tabItem {
VStack {
Image(systemName: "location")
Text("Galway")
}
}.tag(0)
StationListView(cityBikesViewModel: cityBikesViewModel, network: "oslo-bysykkel", tag: 1, selection: $selection)
.tabItem {
VStack {
Image(systemName: "location")
Text("Oslo")
}
}.tag(1)
}
}
Upvotes: 1