Skip to Content
Course content

93: NavigationStack Basics

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Wait, do I just wrap my whole view in a NavigationStack?

Pretty much. Think of the NavigationStack as the manager of your app's visual history. It keeps track of where the user is and where they've been, allowing them to "push" a new view onto the stack and "pop" back to the previous one using that standard back button. If you don't wrap your root view in one, your NavigationLinks simply won't do anything—they'll just sit there like dead buttons.

I usually put the NavigationStack at the very top level of my main view. You only need one for a particular navigation flow. Don't nest them inside each other, or you'll end up with a messy UI where you have multiple navigation bars fighting for space.

struct LibraryView: View {
    var body: some View {
        NavigationStack {
            List {
                Text("The Great Gatsby")
                Text("1984")
                Text("The Hobbit")
            }
            .navigationTitle("My Library")
        }
    }
}

How do I actually move from the list to a detail screen?

The most common way is using a NavigationLink. In the old days of SwiftUI, we used to put the destination view directly inside the link, but that's inefficient because SwiftUI would initialize all those destination views immediately, even if the user never clicked them. Now, we use value-based navigation.

You tell the link: "When this is clicked, send this specific piece of data into the stack." Then, you use a modifier to tell the stack how to handle that data. It's a much cleaner separation of concerns.

struct Book: Hashable {
    let title: String
    let author: String
}

struct LibraryView: View {
    let books = [
        Book(title: "The Great Gatsby", author: "F. Scott Fitzgerald"),
        Book(title: "1984", author: "George Orwell")
    ]

    var body: some View {
        NavigationStack {
            List(books, id: \.title) { book in
                // We pass the 'book' object as the value
                NavigationLink(book.title, value: book)
            }
            .navigationDestination(for: Book.self) { book in
                // This is where the actual transition happens
                BookDetailView(book: book)
            }
            .navigationTitle("My Library")
        }
    }
}

Why do I have to make my data model Hashable?

You probably noticed I added Hashable to the Book struct. This is a requirement for the modern NavigationStack. Because the stack tracks the path of views as a collection of data, it needs a way to uniquely identify each piece of data to know exactly which view to push or pop.

If you're using a simple String or Int, you're already covered because those are Hashable by default. But for your own custom structs, just add the protocol. It's a tiny bit of boilerplate that saves you from a lot of runtime headaches. I've seen plenty of beginners get stuck here, wondering why their navigationDestination isn't firing—9 times out of 10, it's because the data type isn't Hashable.

struct BookDetailView: View {
    let book: Book

    var body: some View {
        VStack(spacing: 20) {
            Text(book.title)
                .font(.largeTitle)
            Text("Written by \(book.author)")
        }
        .navigationTitle("Details")
    }
}



📋 Practical Task

Build a City Travel Guide Navigator

Create a simple app that allows a user to browse a list of cities and view a description for each. Follow these requirements:

  • Create a City struct that conforms to Hashable, containing a name and a description.
  • Set up a NavigationStack containing a List of at least three cities.
  • Use NavigationLink(value:) to pass the City object when a row is tapped.
  • Implement a .navigationDestination(for: City.self) modifier that navigates to a CityDetailView.
  • The CityDetailView should display the city's name as a title and its description in a text block.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.