frzi / swiftui-router

Path-based routing in SwiftUI
MIT License
900 stars 43 forks source link

Navigating to a blank screen issue #64

Closed inwoodev closed 4 months ago

inwoodev commented 4 months ago

Hello, first of all, I do appreciate your effort. Thank you for building such an useful library. I am trying to develop a watch companion app using the swiftui-router and I am facing this issue of navigating to a black or blank?! screen. Perhaps, I may have not used the router properly...I still do need help with the correct implementation of the library.

here are sample codes similar to for what I have done so far:

import SwiftUI
import SwiftUIRouter

struct RouteURL {
    static let authentication = "/auth"
    static let standby = "/auth/standby"
    static let activity = "/auth/activity"
    static let complete = "/auth/complete"
}

@main
struct WatchDemo_Watch_AppApp: App {
    var body: some Scene {
        WindowGroup {
            Router {
                RootView()
            }
        }
    }
}
import SwiftUI
import SwiftUIRouter

struct RootView: View {
    @EnvironmentObject var navigator: Navigator
    var body: some View {
        VStack {
            Route(RouteURL.authentication) {
                AuthenticationView()
                    .onAppear {
                        print("authentication Appear")
                    }
            }
        }
        .onAppear {
            navigator.navigate(RouteURL.authentication)
        }
    }
}
import SwiftUI
import SwiftUIRouter

enum LoginState: Equatable {
    case attemptToLogin
    case login
    case logout
}

struct AuthenticationView: View {
    @State private var loginState: LoginState = .attemptToLogin
    @EnvironmentObject var navigator: Navigator
    var body: some View {
        VStack {
            switch loginState {
            case .attemptToLogin:
                Text("attempt to login")
                ProgressView()
            case .login:
                Route {
                    ActivityRouteView()
                }
            case .logout:
                Text("logout")
            }

        }
        .onAppear {
            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                self.loginState = .logout
            }

            DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
                self.loginState = .login
            }
        }
    }
}

#Preview {
    Router {
        AuthenticationView()
    }
}
import SwiftUI
import SwiftUIRouter

struct ActivityRouteView: View {
    @EnvironmentObject var navigator: Navigator
    var body: some View {
        VStack {
            Route(RouteURL.standby, content: standby)

            Route(RouteURL.activity, content: activity)

            Route(RouteURL.complete, content: complete)
        }
        .onAppear {
            DispatchQueue.main.async {
                navigator.navigate(RouteURL.standby)
                print("navigate to standby")
            }

            DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
                navigator.navigate(RouteURL.activity)
                print("navigate to activity")
            }

            DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                navigator.navigate(RouteURL.complete)
                print("navigate to complete")
            }

            DispatchQueue.main.asyncAfter(deadline: .now() + 7) {
                navigator.navigate("\\", replace: true)
                print("to root")
            }
        }
    }

    var standby: some View {
        Color.blue
    }

    var activity: some View {
        Color.red
    }

    var complete: some View {
        Color.yellow
    }
}

#Preview {
    Router {
        ActivityRouteView()
    }
}

At first, I thought it was a nothing but a preview bug, however, in a real project with a similar router hierarchy, same issue occurs. swiftuiRouterBlankPageIssue

I was expecting to see the color change as below when changing route from authentication to activity and standby views...perhaps it may be a bug, or I might have not used the router correctly. Please help!! swiftuiRouterExpected

frzi commented 4 months ago

Hi 😃

If a Route has sub-routes you will need to add a /* to the path. So your first Route, which is currently

Route(RouteURL.authentication) { // "/auth/"
    // ...
}

should be

Route("auth/*") {
    // ...
}

This means the Route will render its contents if the Navigator's path is /auth, /auth/standby etc. The * is important here, otherwise paths like /auth/standby/ or anything deeper won't be rendered.

This change alone should fix your problem.

inwoodev commented 4 months ago

Thank you for your help~ I could easily fix my problem with your solution. Now everything renders as expected :)