Tengo este caso de uso en el que tengo una vista principal y una vista secundaria. Ambas vistas tienen sus propios ViewModels correspondientes.
ParentView:
struct ParentView: View { @StateObject var parentViewModel = ParentViewModel() var body: some View { NavigationView { List { TextField("Add Name", text: $parentViewModel.newListName) NavigationLink(destination: ChildView()) { Label("Select Products", systemImage: K.ListIcons.productsNr) } } } }ParentViewModel:
class AddListPopoverViewModel: ObservableObject { @Published var newListName: String = "" func saveList() { // some logic to save to CoreData, method would be called via a button // how do I reference "someString" from ChildViewModel in this ViewModel? } }ChildView:
struct ChildView: View { @StateObject var childViewModel = ChildViewModel() var body: some View { NavigationView { List{ Text("Some element") .onTapGesture { childViewModel.alterData() } } } } }ChildViewModel:
class ChildViewModel: ObservableObject { @Published var someString: String = "" func alterData() { someString = "Toast" } } Mi pregunta ahora es, ¿cómo paso el nuevo valor de "someString" de ChildViewModel a ParentViewModel, para hacer más cosas con él? Intenté crear una @StateObject var childViewModel = ChildViewModel() en ParentViewModel, pero eso obviamente no funciona, ya que creará una nueva instancia de ChildViewModel y, por lo tanto, no conoceré los cambios realizados en "someString"
Solución: según lo propuesto por Josh, seguí el enfoque de usar un solo ViewModel en lugar de dos. Para lograr esto, ParentView necesita un modificador .environmentObject .environmentObject(T) .
ParentView:
struct ParentView: View { @StateObject var parentViewModel = ParentViewModel() var body: some View { NavigationView { List { TextField("Add Name", text: $parentViewModel.newListName) NavigationLink(destination: ChildView()) { Label("Select Products", systemImage: K.ListIcons.productsNr) } } }.environmentObject(parentViewModel) } ChildView luego hace referencia a ese objeto de entorno a través @EnvironmentObject sin un inicializador:
struct ChildView: View { @EnvironmentObject var parentViewModel: ParentViewModel var body: some View { NavigationView { List{ Text("Some element") .onTapGesture { parentViewModel.alterData() } } } } }Lo más probable es que use un enlace para esta situación:
struct ChildView: View { @Binding var name: String var body: some View { NavigationView { List{ Text("Some element") .onTapGesture { name = "Altered!" } } } } }Y en el padre:
struct ParentView: View { @StateObject var parentViewModel = ParentViewModel() var body: some View { NavigationView { List { TextField("Add Name", text: $parentViewModel.newListName) NavigationLink(destination: ChildView(name: $parentViewModel.newListName)) { Label("Select Products", systemImage: K.ListIcons.productsNr) } } } } Además, creo que puede eliminar la vista NavigationView de ChildView . Tener ParentView es suficiente.