Comments (6)
OK, seems that I found a little clue, the ContentView struct was being refactored once observed model are updated. The temporary solution is to declare the navigation stack within Model:
import SwiftUI
import NavigationStack
class Model : ObservableObject {
@Published var counter1 : Int = 0
@Published var counter2 : Int = 0
@Published var stack = NavigationStack()
}
struct SecondView: View {
@ObservedObject var model : Model
var body: some View {
VStack() {
Text("2st Page")
Button(action: {
model.counter2 += 1
print(model.counter2)
}, label: {
Text("Press to increase (\(model.counter2))")
})
PopView(label: {
Text("Back")
})
}
}
}
struct ContentView: View {
@ObservedObject var model : Model = Model()
var body: some View {
NavigationStackView(navigationStack: model.stack) {
VStack() {
Text("1st Page")
Button(action: {
model.counter1 += 1
print(model.counter1)
}, label: {
Text("Press to increase (\(model.counter1))")
})
PushView(destination: SecondView(model : model), label: {
Text("Go to 2nd view")
})
}
}
}
}
The reason why refactoring occurs is still not sure though.
from swiftui-navigation-stack.
@StateObject would probably help you here, replace @ObservedObject var model : Model = Model() with @StateObject var model : Model = Model()
from swiftui-navigation-stack.
Hi @xarple what you are experiencing is something related to how SwiftUI works. When you change a Published
property inside an ObservableObject
you are basically asking SwiftUI to recompute the body of the views that depend on that ObservableObject
. In your case your ContentView
relies on Model
and the ContentView
body contains the NavigationStackView
itself. So, what happens here is that you are recreating a new NavigationStackView
each time you change your Model
.
Usually, since the navigation stack manages the navigation throughout the app, what you should consider is moving the NavigationStackView
to the entry point of your app (AppDelegate
or SceneDelegate
). For example:
import SwiftUI
@main
struct NavStackApp: App {
var body: some Scene {
WindowGroup {
NavigationStackView {
ContentView()
}
}
}
}
and your ContentView
would become:
struct ContentView2: View {
@ObservedObject var model : Model = Model()
var body: some View {
VStack() {
Text("1st Page")
Button(action: {
model.counter1 += 1
print(model.counter1)
}, label: {
Text("Press to increase (\(model.counter1))")
})
PushView(destination: SecondView(model : model), label: {
Text("Go to 2nd view")
})
}
}
}
The solution you found is also valid, but it strictly depends on your needs. If it's ok for you to inject the NavigationStack
into the NavigationStackView
your solution is fine. The reason why it works is because it's true that each time you change your model you are recreating your content view and the NavigationStackView
it contains, but this time you don't recreate the NavigationStack
too. The NavigationStack
is always the same (saved by yourself in the model).
from swiftui-navigation-stack.
@StateObject would probably help you here, replace @ObservedObject var model : Model = Model() with @StateObject var model : Model = Model()
Unfortunately, in this case, StateObject
doesn't help us much. It's true that, as Apple suggests, you should go for StateObject
instead of ObservedObject
when the object is created by the view itself and not injected from the outside (as in this specific case). But the behaviour of the ObservableObject
is the same: if it changes, the views that depend on it will be redrawn (i.e. their body will get recomputed).
from swiftui-navigation-stack.
@StateObject would probably help you here, replace @ObservedObject var model : Model = Model() with @StateObject var model : Model = Model()
Unfortunately, in this case,
StateObject
doesn't help us much. It's true that, as Apple suggests, you should go forStateObject
instead ofObservedObject
when the object is created by the view itself and not injected from the outside (as in this specific case). But the behaviour of theObservableObject
is the same: if it changes, the views that depend on it will be redrawn (i.e. their body will get recomputed).
I was commenting on his refactored version with having the NavigationStack inside the model. If his ContentView gets recreated then his model will get reinitialised, including the stack, and he will have the same problem. I know this because my use of NavigationStackView occurs a few screens deep into my App.
So I agree with the views will get redrawn with ObservableObject and StateObject, however the model itself will not get recreated using @StateObject.
I personally use @State in my App for the NavigationStack so I can pass it through bindings to its subviews, but it is the same effect as @StateObject.
Thanks for creating this Repo, my App wouldn't have been the same without it!
from swiftui-navigation-stack.
@brett-eugenelabs Yes, you're right. I thought you were commenting on the first version. Thank you so much for your words 🙏 🙏
from swiftui-navigation-stack.
Related Issues (20)
- Stack Reset / Jump to a completely different view HOT 2
- Transition animation not working HOT 1
- @State variables get reset after pop HOT 3
- Support for iOS 15. HOT 1
- Push doesn't work if app is backgrounded and aware of scenePhase
- Return to the same position in the previous view HOT 2
- Support for Xcode 14 and new SwiftUI API HOT 6
- Previous view completely reloaded after pop HOT 1
- Popping to a specific view
- Callback navigation sometimes doesnt work HOT 1
- iOS 16 transitions malfunctioning HOT 9
- after pop,the previous scrollview auto scroll to top? HOT 6
- Xcode 14 Compiling Issue HOT 6
- not support swipe back HOT 2
- Referencing @Environment(\.scenePhase) var scenePhase breaks navigation when moving app to background
- [Bug]: Clicking on any other window in macOS will return stack to its root
- Value not changed by @Binding
- onappear excuse only first time
- how use in List cell
- after pop,the previous scrollview auto scroll to top?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from swiftui-navigation-stack.