How to know which List item is tapped using Composable Architecture with SwiftUI?

940 Views Asked by At

Given a pretty basic TCA View with a List populated by a ViewStore, how to know which cell in the list is tapped? in onTapGesture, there is no access to the item, since its a scope above. If you add a onTapGesture to the Text, it will not trigger when tapping the whole cell.

WithViewStore(self.store) { viewStore in
  NavigationView {
    List {
      ForEach(viewStore.state.listItems, id: \.self) { item in
        Text(item.title)
      }
    }.onTapGesture {
      print("Tapped row, but no access to item")
    }
  }
}
1

There are 1 best solutions below

1
On

As lorem ipsum mentioned in the comments, the onTapGesture is in the wrong place. It should be associated with the Text. This is how I would do it using your current code:

      List {
          ForEach(viewStore.state.listItems, id: \.self) { item in
             Text(item.title)
               .onTapGesture {
                  viewStore.send(.itemSelected(item))
               }
          }
      }

In your AppState struct you should add a variable to hold the current selection:

var selectedItem: ItemType // you haven't provided a definition, but this should be a class, not a struct

In your AppAction enum you add the case:

public enum SimpleAction {
    case itemSelected(ItemType)
...
}

In your reducer you add (inside your switch):

switch action {
        case let . itemSelected(item):
           // either assign as 
           state.selectedItem = item
           // or do the needful as you require
    }

That said, I would probably enumerate the list to get an index and send the Int index to the reducer instead of the item itself. If anything is unclear (to anyone), please comment and I'll update my response.