DeveloperAcademy-POSTECH / MacC-Team2-Nutty

2 stars 0 forks source link

NavigationState Management with NavigationStack #51

Closed mun9769 closed 1 year ago

mun9769 commented 1 year ago

📌 Issue

ViewModel을 활용한 NavigationStack

class HomeNavigationViewModel: ObservableObject{
    @Published var homePath: [HomeRoute] = []

    func navigate(_ route: HomeRoute)  {
        homePath.append(route)
    }

    func pop() {
        homePath.removeLast()
    }

    func popToRoot() {
        homePath = []
    }
}
public enum HomeRoute {
    case MainView
    case IDCardOCRView
    case SignatureView
...
}

HomeRoute 배열을 관리해주는 HomeNavigationViewModel와 HomeRoute Enum을 정의한다

struct MainView: View {
    @StateObject private var homeNavigation = HomeNavigationViewModel() // 1️⃣

    var body: some View {
        TabView {
            NavigationStack(path: $homeNavigation.homePath) { // 2️⃣
                HomeView()
                    .navigationDestination(for: HomeRoute.self) { route in // 3️⃣
                        switch(route) {
                        case .IDCardOCRView:                    IDCardOCRView()
                        case .SignatureView:                    SignatureView()
                        ...
                }
                .environmentObject(homeNavigation) // 4️⃣

1️⃣ MainView에 ViewModel을 선언한다. 2️⃣ NavigationStack를 선언한다. homeNavigation.homePath에 새로운 뷰가 추가되면 화면에 새로운 뷰가 생성된다. 3️⃣ .navigationDestination(for:) 함수는 view를 전환시킨다 4️⃣ 다음뷰가 homeNavigation에 접근해야하기 때문에 environmentObject로 전달한다.

뷰전환방법1

struct ApplyTypeView: View {
    @EnvironmentObject var homeNavigation: HomeNavigationViewModel // 1️⃣

    var body: some View {
            Button{
                homeNavigation.navigate(. SignatureView) // 2️⃣
            } label: {
                    Text("신청")
...

1️⃣ homeNavigation을 선언한다 2️⃣ homeNavigation.navigate 함수를 통해 이동하고 싶은 뷰를 추가한다

뷰전환방법2

    var body: some View {
          NavigationStack{
                NavigationLink(destination: IDCardConfirmEditView(image: $captureImage)) {
                    Text("다음")
                ...
     }

NavigationLink를 사용해서 뷰 전환을 해줄 수 있다. 장점: Binding 변수를 다음 뷰에게 넘겨줄 수 있다. 특징: homePath에 쌓이지 않는다. 그래서 dimiss 버튼을 눌렀을 때 전전단계의 뷰로 넘어갈 수도 있다

뷰전환방법3

.navigationDestination(isPresented: $isPostCodeViewPresented) {
    PostCodeInputView(isPostCodeViewPresented: $isPostCodeViewPresented,
                                       cityAddress: $address.cityAddress)
}

장점: Binding 변수를 다음 뷰에게 넘겨줄 수 있다. 특징: homePath에 쌓이지 않는다.

상태값이 두 개 이상인 뷰 전환하는 방법 ```swift struct StepView: View { enum StepViewState { case FIRST case SECOND } let state: StepViewState init(state: StepViewState) { self.state = state } ``` StepView는 두 개의 state가 존재합니다. enum으로 state를 구분해주었습니다. 그럼 NavigationStack에서 어떻게 상태를 구분해서 StepView를 부를 수 있을까요? ```swift public enum HomeRoute { case MainView case StepView_First case StepView_Second ... } ``` HomeRoute에 StepView에 대한 두가지 값을 정의해줍니다. ```swift HomeView() .navigationDestination(for: HomeRoute.self) { route in switch(route) { case .StepView_First: StepView(state: .FIRST) case .StepView_Second: StepView(state: .SECOND) ``` .navigationDestination(for:) 함수에 case를 나눠주면 내가 원하는 StepView를 부를 수 있습니다.

고민

꼭 NavigationStack을 사용해야 rootView로 이동할 수 있는지 모르겠다 Binding 값을 다음뷰에 넘겨주는 경우가 있는데 이거 넘겨주면 안된다고 생각함.

참고

https://medium.com/@sarimk80/navigationstack-with-viewmodel-c0ec223cf16b

ge-um commented 1 year ago

잘 읽었습니다 에렌~