I am trying to pass data from one View to another using @StateObject
navigating using NavigationStack
and NavigationPath
. In my case I can't use NavigationLink
.
To achieve that a came up with this code:
struct ContentView: View {
@State private var inputValue: String = ""
@StateObject private var dataStore = DataStore()
@StateObject var coordinator = Coordinator()
var body: some View {
NavigationStack(path: $coordinator.path) {
VStack {
TextField("Enter a value", text: $inputValue)
.padding()
Button("Next") {
dataStore.stringValue = inputValue
coordinator.gotoNext()
}
.padding()
}
.navigationDestination(for: Destination.self) { destination in
switch destination {
case .ContentView:
ContentView()
case .NextView:
NextView()
}
}
.environmentObject(coordinator)
}
}
}
The first View
struct NextView: View {
@StateObject private var dataStore = DataStore()
@EnvironmentObject var coordinator: Coordinator
var body: some View {
VStack {
Text("Value from previous view:")
.padding()
Text(dataStore.stringValue)
.padding()
Button {
coordinator.gotoHomePage()
} label: {
Text("Back to home page")
}
}
}
}
The second View
class Coordinator: ObservableObject {
@Published var path = NavigationPath()
func gotoHomePage() {
print("Go to Home")
path.removeLast(path.count)
}
func gotoNext() {
print("gotoNext")
path.append(Destination.NextView)
}
func goBack() {
print("goBack")
path.removeLast()
}
}
The Coordinator (NavigationPath)
class DataStore: ObservableObject {
@Published var stringValue: String = ""
}
enum Destination {
case ContentView
case NextView
}
Data Structure and navigation
When I run the code, I can navigate forward (to the NextView
, but no values appears and when I try to get back to the ContentView
, the code crashs.
Looks like there aren't data in de enviroment
neither DataStore
are holding value.
What I'm doing wrong?
** Update 1
When I move the environment set to the App struct then the code works fine:
import SwiftUI
@main
struct NavigationStackApp: App {
@StateObject var dataStore = DataStore()
@StateObject var coordinator = Coordinator()
private var root = ContentView()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(coordinator)
.environmentObject(dataStore)
}
}
}
** Update 2
So If I want to do this from a view struct
instead of App struct
I should create an mainView
to set the environment and encapsulate the first view that will use the environment objects:
struct MainView:View {
@StateObject var dataStore = DataStore()
@StateObject var coordinator = Coordinator()
var body: some View {
ContentView()
.environmentObject(coordinator)
.environmentObject(dataStore)
}
}