Yes, that's a lot better!
Indeed this is very similar to a fairly complex app that I have been working on. The way I solved is as follows (not necessarily saying it's the best way, FWIW):
First, I tried to push the sheet as high up in the view hierarchy as possible. You want to be able to bring up the sheet even when the item detail view is not there. In this particular example, you had in the root view and that works pretty well. If you'd rather move it inside the ItemsView
you might want to move the list to that component instead.
Second, I define edit actions on both the detail view and on the parent where editing can be triggered from a list. You already had the latter, but the former was missing. Something along these lines:
enum ItemAction: Equatable {
case startEditing
}
Then you can trigger this action from the button inside the details view:
Button("Edit") {
viewStore.send(.startEditing)
}
Then, and this is the crucial bit, in your itemsReducer
you need to handle this action via the case item(id: Item.ID, action: ItemAction)
you already had in place. The idea is to return an effect with .showEditItem
so that it follows the same path as the other one triggered from the list view.
case .item(let id, let action):
guard action == .editItem,
let itemState = state.itemStates[id: id]
else { return .none }
return .init(value: .showEditItem(itemState))
This should be all you need to get edit to work from both paths. I tried it and it seems to work. Again, this is how I have been doing this kind of thing, and it feels right to me, but I could be wrong.
For the EditItemState
modeling question I don't think I have much to add since that would depend a lot on how this code will evolve etc.