【Swift】TCAでモーダル遷移時に値を渡す

# はじめに
TCAでモーダル遷移時にSubViewに値を渡す方法を記録しておきます。
間違っている箇所やもっと良い方法がある箇所があるかもしれません。
もしあればコメントで教えていただけると助かります。

# やりたいこと
![Simulator Screen Recording - iPhone 14 Pro - 2023-09-16 at 20.55.40.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/49d9fc5f-d7b5-3288-319a-151909e0086f.gif)

# 実装
`ContentView`から`SubView`に遷移させます。

### ContentView
```ContentView.swift
import SwiftUI

struct ContentView: View {
    @ObservedObject private var viewStore: ViewStoreOf<ContentReducer>
    
    let store: StoreOf<ContentReducer>
    
    init(store: StoreOf<ContentReducer>) {
        self.store = store
        self.viewStore = ViewStore(store, observe: { $0 })
    }
    
    var body: some View {
        VStack(spacing: 30) {
            Text(viewStore.count.description)
            
            Button {
                viewStore.send(.plusButtonTapped)
            } label: {
                Text("+")
            }

            Button {
                viewStore.send(.minusButtonTapped)
            } label: {
                Text("-")
            }
            
            Button {
                viewStore.send(.onPresentButtonTapped)
            } label: {
                Text("表示")
            }
        }
        .sheet(store: store.scope(state: \.$subState, action: ContentReducer.Action.subAction)) { store in
            SubView(store: store)
        }
    }
}
```

```ContentReducer.swift
import Foundation
import ComposableArchitecture

public struct ContentReducer: Reducer {
    public init() {}

    // MARK: - State
    public struct State: Equatable {
        @PresentationState var subState: SubReducer.State?
        var count = 0
        
        public init() {}
    }

    // MARK: - Action
    public enum Action: Equatable {
        case subAction(PresentationAction<SubReducer.Action>)
        case onPresentButtonTapped
        case plusButtonTapped
        case minusButtonTapped
    }

    // MARK: - Reducer
    public var body: some ReducerOf<Self> {
        Reduce { state, action in
            switch action {
            case .onPresentButtonTapped:
                state.subState = .init(count: state.count) // ここで代入されることによってモーダルが表示される
                return .none
            case .subAction:
                return .none
            case .plusButtonTapped:
                state.count += 1
                return .none
            case .minusButtonTapped:
                state.count -= 1
                return .none
            }
        }
        .ifLet(\.$subState, action: /Action.subAction) {
            SubReducer() // ここがないと`dismiss`できなくなる
        }
    }
}
```

### SubView
```SubView.swift
import SwiftUI

struct SubView: View {
    @ObservedObject private var viewStore: ViewStoreOf<SubReducer>
    
    let store: StoreOf<SubReducer>
    
    init(store: StoreOf<SubReducer>) {
        self.store = store
        self.viewStore = ViewStore(store, observe: { $0 })
    }
    
    var body: some View {
        VStack(spacing: 30) {
            Text(viewStore.count.description)
            
            Button {
                viewStore.send(.onDismissButtonTapped)
            } label: {
                Text("閉じる")
            }
        }
    }
}
```

```SubReducer.swift
import Foundation
import ComposableArchitecture

public struct SubReducer: Reducer {
    @Dependency(\.dismiss) var dismiss // モーダルを閉じるために必要

    public init() {}

    // MARK: - State
    public struct State: Equatable {
        var count: Int // ここで欲しい値を受け取る
        
        public init(count: Int) {
            self.count = count
        }
    }

    // MARK: - Action
    public enum Action: Equatable {
        case onDismissButtonTapped
    }

    // MARK: - Reducer
    public var body: some ReducerOf<Self> {
        Reduce { state, action in
            switch action {
            case .onDismissButtonTapped:
                return .run { _ in await self.dismiss() } // ここで閉じる
            }
        }
    }
}
```

# おわり
TCAはむずいです