nalexn / clean-architecture-swiftui

SwiftUI sample app using Clean Architecture. Examples of working with CoreData persistence, networking, dependency injection, unit testing, and more.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Another Question about Navigation/Routing

Patrick3131 opened this issue · comments

Hey Alex, thanks a lot for your example application.

I am creating another sample app based on the provided architecture of your example to get a better understanding of SwiftUI and Combine.

I have another problem with the navigation/routing. I basically copied your approach but I have these weird back and forth navigation behaviour, maybe you could take a look at my code. I have been going through the Stackoverflow topics, but I wasn't able to fix it and at the same time keep your routing example.

struct CategoriesList: View {
    @Environment(\.locale) private var locale: Locale
    @Environment(\.injected) private var injected: DIContainer
    @State private var routingState: Routing = .init()
    private var routingBinding: Binding<Routing> {
        print(routingState)
        return $routingState.dispatched(to: injected.appState, \.routing.categories)
    }
    private var categories = Category.allCases
    var body: some View {
        content
            .onReceive(routingUpdate) { value in
                print(value)
                self.routingState = value
        }
    }
    
    
    private var content: some View {
        NavigationView {
            List(self.categories) { category in
                NavigationLink(
                    destination: Exercises(),
                    tag: category.rawValue,
                    selection: self.routingBinding.categories) {
                        CategorieCell(name: category.rawValue)
                }
            }.navigationBarTitle("Categories")
        }
        
        
    }
}

// MARK: - State Updates
private extension CategoriesList {
    var routingUpdate: AnyPublisher<Routing, Never> {
        injected.appState.updates(for: \.routing.categories)
    }
}

extension CategoriesList {
    struct Routing: Equatable {
        var categories: String?
    }
}



struct ExerciseDetail: View {
    var body: some View {
        Text("Hello DetailsView")
    }
}

Link to the file:
https://github.com/Patrick3131/LearnHockey/blob/dev/LearnHockey/UI/Screens/CategoriesList.swift

Thanks!

Hi @Patrick3131

So I could find two issues in your code. The main one that was causing the weird back and forth navigation was this code:

extension Category: Identifiable {
    var id: UUID { UUID()}
}

You are returning a random UUID each time this computed property is called, which totally confuses SwiftUI's list.

Here is a correct revision:

extension Category: Identifiable {
    var id: String { self.rawValue }
}

Another issue is that you didn't inject the DIContainer in the hierarchy, and the default value was used instead. You should do this:

var body: some View {
     CategoriesList().inject(container)
}

Thanks a lot, it works!