07-19-2023, 12:34 AM
# Problem
In Order to achieve a clean look and feel of the App's code, I create ViewModels for every View that contains logic.
A normal ViewModel looks a bit like this:
```
class SomeViewModel: ObservableObject {
@Published var state = 1
// Logic and calls of Business Logic goes here
}
```
and is used like so:
```
struct SomeView: View {
@ObservedObject var viewModel = SomeViewModel()
var body: some View {
// Code to read and write the State goes here
}
}
```
This workes fine when the Views Parent is not being updated. If the parent's state changes, this View gets redrawn (pretty normal in a declarative Framework). **But** also the ViewModel gets recreated and does not hold the State afterward. This is unusual when you compare to other Frameworks (eg: Flutter).
*In my opinion, the ViewModel should stay, or the State should persist.*
If I replace the ViewModel with a `@State` Property and use the `int` (in this example) directly it stays persisted and **does not get recreated**:
```
struct SomeView: View {
@State var state = 1
var body: some View {
// Code to read and write the State goes here
}
}
```
This does obviously not work for more complex States. And if I set a class for `@State` (like the ViewModel) more and more Things are not working as expected.
# Question
- Is there a way of not recreating the ViewModel every time?
- Is there a way of replicating the `@State` Propertywrapper for `@ObservedObject`?
- Why is @State keeping the State over the redraw?
I know that usually, it is bad practice to create a ViewModel in an inner View but this behavior can be replicated by using a NavigationLink or Sheet.<br>
Sometimes it is then just not useful to keep the State in the ParentsViewModel and work with bindings when you think of a very complex TableView, where the Cells themself contain a lot of logic.<br>
There is always a workaround for individual cases, but I think it would be way easier if the ViewModel would not be recreated.
# Duplicate Question
I know there are a lot of questions out there talking about this issue, all talking about very specific use-cases. Here I want to talk about the general problem, without going too deep into custom solutions.
# Edit (adding more detailed Example)
When having a State-changing ParentView, like a list coming from a Database, API, or cache (think about something simple). Via a `NavigationLink` you might reach a Detail-Page where you can modify the Data. By changing the data the reactive/declarative Pattern would tell us to also update the ListView, which would then "redraw" the `NavigationLink`, which would then lead to a recreation of the ViewModel.
I know I could store the ViewModel in the ParentView / ParentView's ViewModel, but this is the wrong way of doing it IMO. And since subscriptions are destroyed and/or recreated - there might be some side effects.
In Order to achieve a clean look and feel of the App's code, I create ViewModels for every View that contains logic.
A normal ViewModel looks a bit like this:
```
class SomeViewModel: ObservableObject {
@Published var state = 1
// Logic and calls of Business Logic goes here
}
```
and is used like so:
```
struct SomeView: View {
@ObservedObject var viewModel = SomeViewModel()
var body: some View {
// Code to read and write the State goes here
}
}
```
This workes fine when the Views Parent is not being updated. If the parent's state changes, this View gets redrawn (pretty normal in a declarative Framework). **But** also the ViewModel gets recreated and does not hold the State afterward. This is unusual when you compare to other Frameworks (eg: Flutter).
*In my opinion, the ViewModel should stay, or the State should persist.*
If I replace the ViewModel with a `@State` Property and use the `int` (in this example) directly it stays persisted and **does not get recreated**:
```
struct SomeView: View {
@State var state = 1
var body: some View {
// Code to read and write the State goes here
}
}
```
This does obviously not work for more complex States. And if I set a class for `@State` (like the ViewModel) more and more Things are not working as expected.
# Question
- Is there a way of not recreating the ViewModel every time?
- Is there a way of replicating the `@State` Propertywrapper for `@ObservedObject`?
- Why is @State keeping the State over the redraw?
I know that usually, it is bad practice to create a ViewModel in an inner View but this behavior can be replicated by using a NavigationLink or Sheet.<br>
Sometimes it is then just not useful to keep the State in the ParentsViewModel and work with bindings when you think of a very complex TableView, where the Cells themself contain a lot of logic.<br>
There is always a workaround for individual cases, but I think it would be way easier if the ViewModel would not be recreated.
# Duplicate Question
I know there are a lot of questions out there talking about this issue, all talking about very specific use-cases. Here I want to talk about the general problem, without going too deep into custom solutions.
# Edit (adding more detailed Example)
When having a State-changing ParentView, like a list coming from a Database, API, or cache (think about something simple). Via a `NavigationLink` you might reach a Detail-Page where you can modify the Data. By changing the data the reactive/declarative Pattern would tell us to also update the ListView, which would then "redraw" the `NavigationLink`, which would then lead to a recreation of the ViewModel.
I know I could store the ViewModel in the ParentView / ParentView's ViewModel, but this is the wrong way of doing it IMO. And since subscriptions are destroyed and/or recreated - there might be some side effects.