简体   繁体   中英

SwiftUI: How to pass selected item back to parent using ViewModels

I'm trying to shape out the best way to pass the info back from child to parent when both use View Models and need the item to perform some work. There are a lot of similar topics on SO, but none seems to tackle the issue that I've got. I understand there might be multiple solutions to solve this project, but none of them convince me to be correct.

Parent

screen when you have a selected item and can save it later

struct ParentView: View {
    @StateObject viewModel = ParentViewModel()
}

class ParentViewModel: : ObservableObject {
    @Published var selectedItem: Item?
    
    func saveSelectedItem() {
       // some logic to perform the request and save selectedItem, of course when it is not nil
    }
}

ChildView

Fetches all the possible items and allows selecting the item which should be later passed to parent.

struct ChildView: View {
    @StateObject viewModel = ChildViewModel()

    **(Problem)**
    
    // presents the list of all the items and highlights the current one (if not nil)
    // on click sends the info back to Parent
}

class ChildViewModel: : ObservableObject {
    @Published var items: [Item] = []
   
    **(Problem)**
    
    func loadItems() {
       // fetches the items and sorts them
    }
}

What I would like to do is to pass selectedItem to the ChildView and be notified when it is selected there on the list, but the child view model needs this to properly sort the items.

PROBLEM

  1. What is the best approach to pass the selectedItem to the child and use it in ViewModel ?

If I pass it as a Binding then the ChildView owns it, and I require this in my ChildViewModel to sort the items based on selectedItem .

If I perform an action to highlight the selected item based on state of the ChildViewModel (items) and selectedItem isn't a bit of a mess?

struct ChildView: View {
    @StateObject viewModel = ChildViewModel()
    @Binding var selectedItem: Item? // How can I use this in ChildViewModel, I need it to sort fetched items properly
}
  1. I guess I should not pass binding to ViewModel as it is part of the SwiftUI framework?

class ChildViewModel: : ObservableObject {
    @Published var items: [Item] = []
    @Binding var selectedItem: Item? // I guess this is not correct, I don't even know how to pass it here
}
  1. I know I can use completion block and initialize ChildViewModel with wrappedValue of the selectedItem but I would love to use SwiftUI/Combine approach.

In SwiftUI, you can use a combination of @Binding and @State to pass data back to a parent view.

Here's an example:

 struct ParentView: View {
  @State private var selectedItem: Item?

  var body: some View {
    VStack {
      // Other views...

      ChildView(selectedItem: $selectedItem)
    }
  }
}

struct ChildView: View {
  @Binding var selectedItem: Item?

  var body: some View {
    List {
      // List of items...

      Button(action: {
        self.selectedItem = item
      }) {
        Text(item.name)
      }
    }
  }
}

In this example, the ChildView has a selectedItem binding that is passed in from the parent view. When a user taps on one of the items in the list, the selectedItem is updated with the selected item. This change is automatically propagated back to the parent view because of the @Binding property wrapper.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM