frzi / swiftui-router

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

Nested routes without parent being rerendered on child navigation #31

Closed blommegard closed 2 years ago

blommegard commented 2 years ago

Hi and thanks for a very nice library!

I am wondering if it would be possible to navigate between two and three without one being rerendered?

The way we use this is that the view model of one handles data fetching and is then passed to two (and three) via .environemntObject(). But when navigating between those one is recreated on all navigation steps as well.

@main
struct MyApp: App { 
    var body: some Scene {
        WindowGroup {
            Router(initialPath: "/one/two/three") {
                Route(path: "/one/*") {
                    Text("One")

                    Route(path: "/one/two/*") {
                        Text("Two")

                        Route(path: "/one/two/three") {
                            Text("Three")
                        }
                    }
                }
            }
        }
    }
}
frzi commented 2 years ago

Not that I'm aware of, no. But this generally shouldn't cause for any problems.

If you're fetching data it's advised to do this in a view's .onAppear.

Text("One")
    .onAppear { print("Hello One") }

Regardless of how often you're navigating, you'll notice this will only get called once :smile: This is the perfect moment for views to fetch asynchronous data or perform tasks that only need to run the first time they appear.

An example:

struct SomeAsyncDataView: View {
    @StateObject private var viewModel = MyViewModel()

    var body: some View {
        Group {
            if !viewModel.data.isEmpty {
                Route(path: "subroute/*", content: AnotherView())
                    .environmentObject(viewModel)
            }
            else {
                Text("Loading...")
            }
        }
        .onAppear { viewModel.fetch() }
        .onDisappear { viewModel.cancel() }
    }
}

Thanks for your comments!

blommegard commented 2 years ago

Thanks for the quick reply.

After some investigation I think our issue was that we used @StateObject in a none correct way and it should now be solved!