Home > Net >  SwiftUI: How to persist state through different views?
SwiftUI: How to persist state through different views?

Time:11-25

I have a JSON file of "Countries" and there is a field isFavorite which is a boolean value of false in the JSON.

I have in my ContentView, a list of countries and when you click on the heart beside them, it does the following:

if country.favorite {
    Image(systemName: "heart.fill").foregroundColor(.red).onTapGesture {
        countries[index].isFavorite.toggle()
    }
} else {
    Image(systemName: "heart").foregroundColor(.red).onTapGesture {
        countries[index].isFavorite.toggle()
    }
}

this is fine and works while in this view. When I move over to FavoritesView, all the countries isFavorite values are lost and set to the default false which was in the JSON. I keep getting the view to show 'No Favorites!'. How do I retain the altered state between views?

Below is some of my code:

MainView

import SwiftUI

struct MainView: View {
    @State var countries: [Country] = Bundle.main.decode("Countries.json")
      
    var body: some View {
        TabView {
            ContentView(countries: $countries)
                .tabItem {
                    Label("Menu", systemImage: "list.dash")
                }
            MapView()
                .tabItem {
                    Label("Map", systemImage: "square.and.pencil")
                }
            FavoritesView(countries: $countries)
                .tabItem {
                    Label("Favorites", systemImage: "square.and.pencil")
                }
        }
    }
}


func hasFavorites() -> [Country] {
    var favorites: [Country] = []
    
    countries.forEach { country in
        if country.isFavorite == true {
            favorites.append(country)
        }
    }
    
    return favorites 
}

FavoritesView

struct FavoritesView: View {
    @Binding var countries: [Country]
    
    var body: some View {
        if hasFavorites().count > 1 {
            Text("test test: User has Favorites!")
        } else {
            Text("no favorites!")
        }
    }
}

CodePudding user response:

Right now, your hasFavorites function exists outside of your views. In fact, it's unclear from the code you've included how it's accessing countries, since, again, it is outside of the views.

I'd refactor it to be inside the view where you need it. I'd also make it a computed property and use filter to find only the countries where isFavorite is true rather than doing the manual loop/append that you're doing right now.

struct FavoritesView: View {
    @Binding var countries: [Country]
    
    var favorites : [Country] {
        return countries.filter { $0.isFavorite }
    }
    
    var body: some View {
        if favorites.count > 1 {
            Text("test test: User has Favorites!")
        } else {
            Text("no favorites!")
        }
    }
}

  • Related