맛동산이

SwiftUI) TAC - NestedAction, Action의 가독성을 높이기 위한 방법 본문

앱/SwiftUI

SwiftUI) TAC - NestedAction, Action의 가독성을 높이기 위한 방법

진ddang 2024. 9. 17. 04:40

TCA의 큰 흐름은, 뷰가 존재하고, 뷰에서의 이벤트를 감지해서 Action으로 그리고 해당 Action을 Effect로, Effect를 통해서 State를 변경해주는 방법이다.

View→Action→Effect→State→View

의 큰 흐름이 된다.

이때 Action이 방대해지면, Action을 명확하게 어떠한 액션인지 구분하기 어렵게 된다.

이를 해결하기 위해서 NestedAction을 통해서 액션의 타입을 명확하게 구분해주는 것으로

코드의 명확성과 가독성을 올리는 방법을 소개하려고 한다.

enum Action {
	case onAppear
	case task
	case tapOpenButton
	//현재는 taskResult는 duplicated될 예정이기 때문에 Result를 사용하는게 좋다.
	case upLoadResponse(TaskResult<UserInfo>)
	case dismissFeature
	case tapCloseButton
}

이러한 Action이 있다고 했을때

최종적으로 nestedAction을 통해서 다음과 같은 형태로 변경해 주려고 한다.

enum Action {
  case view(ViewAction)
  case internal(InternalAction)
  case destination(PresentationAction<Destination>)
  case delegate(DelegateAction)

  enum ViewAction {
    case onAppear
    case task
    case tapOpenButton
    case tapCloseButton
  }

  enum InternalAction {
    case uploadResponse(TaskResult<UserInfo>)
  }

  enum Destination {
    case profile(Profile.State)
    case favourites(Favourites.State)
  }

  enum DelegateAction {
    case dismissFeature
  }
}

이러한 형태로 Action을 나누게 되면 가독성이 높아지지만,

이를 사용하는 Reducer를 보게되면 다음과 같다.

Reduce { state, action in 
  switch action {
  case .view(.onAppear): ...
  case .view(.task): ...
  case .internal(.downloadResponse): ...
  case .destination(.presented(.userProfile)): ...
  case .delegate: ...
  case .view: ...
  }
}

혹은

Reduce<State, Action> { state, action in 
	switch actino {
	case let .view(viewAction):
		switch viewAction {
		......
		}
	case let .internal(internalAction):
		switch internalAction {
		....
		}
	case let .delegate(delegateAction):
		switch delegateAction {
		...
		}
	}

이런식으로 나눠서 가독성을 높일수 있다.

내부적으로 Action을 크게

  • ViewAction : 실제로 뷰 내부의 동작
  • InternalAction : 내부적으로 async await등 api 콜 Action
  • DelegateAction : delegate 액셕
  • DestinationAction : 뷰이동을 위한 액션

으로 나눠서 사용하면 더욱더 좋다.


좀더 가독성 있도록, 혹은 사용성을 높이기 위한 방법으로는 Protocol을 추천한다.

protocol TCAAction {
	associatedtype ViewAction
	associatedtype InternalAction
	associatedtype DelegateAction
	
	static func view(_:ViewAction) -> Self
	static func `internal`(_:InternalAction) -> Self
	static func delegate(_: DelegateAction) -> Self
}
  • associatedtype은 프로토콜에서 generic을 사용하기 위한 방법입니다. (placeHolder 타입이라고 생각하면 됩니다.)

이를 통해서 잊지 않고 Action을 구조적으로 사용할수 있도록 합니다.

반응형