Home > Net >  View doesn't update until app/preview is re-opened
View doesn't update until app/preview is re-opened

Time:04-04

Question: How can I go from Login() back to the Home() without restarting the app/preview? I have a feeling it has to do with the variable not being @State but I don't know how to make add @State to a global variable.

Here is my code:

import SwiftUI

var isLoggedIn:Bool {
    get {
        // Get the standard UserDefaults as "defaults"
        let defaults = UserDefaults.standard

        // Makes the "welcomeString" variable whatever the saved value for "welcome_string" is
        return defaults.bool(forKey: "isLoggedIn")
    }
    set (newValue) {
        // Get the standard UserDefaults as "defaults"
        let defaults = UserDefaults.standard

        // Saves what the "welcomeString" variable was just set to as the saved value for "welcome_string"
        defaults.set(newValue, forKey: "isLoggedIn")
    }
}


struct ContentView: View {
  var body: some View {
    if isLoggedIn {
    Home()
    } else {
      Login()
    }
  }
}

struct Login: View {
  var body: some View {
    Button(action: {
      isLoggedIn = true
    }) {
      Text("Click to login")
    }
  }
}

struct Home: View {

  private enum Tab: Hashable {
    case schedule
    case messaging
    case home
    case resources
    case settings
  }

  @State private var selectedTab: Tab = .home

  var body: some View {
    VStack {
      TabView(selection: $selectedTab) {
        One()
          .tag(Tab.home)
          .tabItem {
            Label("One", systemImage: "note")
          }
        Two()
          .tag(Tab.home)
          .tabItem {
            Label("Two", systemImage: "note")
          }
        Three()
          .tag(Tab.home)
          .tabItem {
            Label("Three", systemImage: "note")
          }
        Four()
          .tag(Tab.home)
          .tabItem {
            Label("Four", systemImage: "note")
          }
      }
    }
  }
}

struct One: View {
  var body: some View {
    Text("One")
  }
}

struct Two: View {
  var body: some View {
    Text("Two")
  }
}

struct Three: View {
  var body: some View {
    Text("Three")
  }
}

struct Four: View {
  var body: some View {
    Button(action: {
      isLoggedIn = false
    }) {
      Text("Logout")
    }
  }
}


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

CodePudding user response:

I do not know why you having this simple issue, you cannot depend on value update of a variable if it is not wrapped with the way SwiftUI works, how ever here is first way for you depending on your approach in your question, do not forget that simulator is not working always correct with UserDefaults, so it may not working in the way that it should, then try use on real device:

struct ContentView: View {
    
    @State private var isLoggedIn: Bool = { return UserDefaults.standard.bool(forKey: "isLoggedIn") }()
    
    var body: some View {
        
        if (isLoggedIn) {
            Home(isLoggedIn: $isLoggedIn)
        }
        else {
            Login(isLoggedIn: $isLoggedIn)
        }  
    }
}

func updateLog(_ newValue: Bool) { UserDefaults.standard.set(newValue, forKey: "isLoggedIn") }


struct Login: View {
    
    @Binding var isLoggedIn: Bool
    var body: some View {
        Button("Tap to login") { isLoggedIn = true; updateLog(true) }
    }
}

struct Home: View {
    
    private enum Tab: Hashable {
        case schedule
        case messaging
        case home
        case resources
        case settings
    }
    
    @State private var selectedTab: Tab = .home
    @Binding var isLoggedIn: Bool
    
    var body: some View {
        VStack {
            TabView(selection: $selectedTab) {
                One()
                    .tag(Tab.home)
                    .tabItem {
                        Label("One", systemImage: "note")
                    }
                Two()
                    .tag(Tab.home)
                    .tabItem {
                        Label("Two", systemImage: "note")
                    }
                Three()
                    .tag(Tab.home)
                    .tabItem {
                        Label("Three", systemImage: "note")
                    }
                Four(isLoggedIn: $isLoggedIn)
                    .tag(Tab.home)
                    .tabItem {
                        Label("Four", systemImage: "note")
                    }
            }
        }
    }
}

struct One: View {
    var body: some View {
        Text("One")
    }
}

struct Two: View {
    var body: some View {
        Text("Two")
    }
}

struct Three: View {
    var body: some View {
        Text("Three")
    }
}

struct Four: View {
    @Binding var isLoggedIn: Bool
    var body: some View {
        Button("Logout") { isLoggedIn = false; updateLog(false) }
    }
}

Second way:

struct ContentView: View {
    @AppStorage("isLoggedIn") var isLoggedIn: Bool = false
    var body: some View {
        
        if (isLoggedIn) {
            Home()
        }
        else {
            Login()
        }
    }
}

struct Login: View {
    @AppStorage("isLoggedIn") var isLoggedIn: Bool = false
    var body: some View {
        Button("Tap to login") { isLoggedIn = true }
    }
}

struct Home: View {
    
    private enum Tab: Hashable {
        case schedule
        case messaging
        case home
        case resources
        case settings
    }
    
    @State private var selectedTab: Tab = .home
    @AppStorage("isLoggedIn") var isLoggedIn: Bool = false
    
    var body: some View {
        VStack {
            TabView(selection: $selectedTab) {
                One()
                    .tag(Tab.home)
                    .tabItem {
                        Label("One", systemImage: "note")
                    }
                Two()
                    .tag(Tab.home)
                    .tabItem {
                        Label("Two", systemImage: "note")
                    }
                Three()
                    .tag(Tab.home)
                    .tabItem {
                        Label("Three", systemImage: "note")
                    }
                Four()
                    .tag(Tab.home)
                    .tabItem {
                        Label("Four", systemImage: "note")
                    }
            }
        }
    }
}

struct One: View {
    var body: some View {
        Text("One")
    }
}

struct Two: View {
    var body: some View {
        Text("Two")
    }
}

struct Three: View {
    var body: some View {
        Text("Three")
    }
}

struct Four: View {
    @AppStorage("isLoggedIn") var isLoggedIn: Bool = false
    var body: some View {
        Button("Logout") { isLoggedIn = false }
    }
}
  • Related