[Swift] ReactorKit에서 사용하는 주요 컴포넌트와 그 역할: Reactor, Action, Mutation 등 ReactorKit의 주요 컴포넌트를

작성일 :

Swift에서 ReactorKit 사용하는 법

ReactorKit는 Swift 개발자들이 비즈니스 로직을 깔끔하고 직관적으로 관리할 수 있도록 돕는 라이브러리입니다. 이 글에서는 ReactorKit의 주요 컴포넌트인 Reactor, Action, Mutation에 대해 자세히 설명하고, 각각의 역할과 사용 방법을 다룹니다.

ReactorKit의 개요

ReactorKit는 Model-View-ViewModel(MVVM) 패턴에 Reactor라는 개념을 추가하여, 상태(state)를 관리하고, 변화를 추적하며, 간단한 비즈니스 로직을 구현할 수 있게 해줍니다. ReactorKit는 Reactor, Action, Mutation, State라는 네 가지 주요 요소로 구성되어 있습니다.

Reactor

Reactor는 앱 상태를 추상화한 것으로, 상태 변화를 관리하고, 비즈니스 로직을 포함합니다. Reactor는 다음과 같은 프로퍼티와 메소드를 가집니다:

  • initialState: 초기 상태를 정의합니다.
  • action: 사용자로부터 발생하는 모든 액션을 받아들입니다.
  • mutation: 액션(action)을 변환하여 상태 변화를 만드는 반응 객체입니다.
  • state: 최종 상태를 나타내며, 화면에 반영됩니다.
swift
import ReactorKit
import RxSwift

class MyReactor: Reactor {
    enum Action {
        case doSomething
    }

    enum Mutation {
        case setLoading(Bool)
        case setResult(String)
    }

    struct State {
        var isLoading: Bool = false
        var result: String?
    }

    let initialState: State = State()

    func mutate(action: Action) -> Observable<Mutation> {
        switch action {
        case .doSomething:
            return Observable.concat([
                Observable.just(Mutation.setLoading(true)),
                // API call or some async task
                Observable.just(Mutation.setResult("Hello, ReactorKit")),
                Observable.just(Mutation.setLoading(false))
            ])
        }
    }

    func reduce(state: State, mutation: Mutation) -> State {
        var newState = state
        switch mutation {
        case .setLoading(let isLoading):
            newState.isLoading = isLoading
        case .setResult(let result):
            newState.result = result
        }
        return newState
    }
}

Action

Action은 사용자 인터페이스에서 발동되는 모든 이벤트의 열거형입니다. 여기에는 버튼 클릭, 텍스트 입력, 스크롤 등의 이벤트가 포함될 수 있습니다. ReactorAction을 받아 Mutation으로 변환합니다.

swift
class MyReactor: Reactor {
    enum Action {
        case buttonClicked
        case textTyped(String)
    }

    // ... other code
}

Mutation

MutationAction이 실제로 변경되어 State로 반영되기 전에 잠시 나타나는 변형입니다. 즉, Action이 상태 변화에 어떤 영향을 미칠지 결정하는 중간 단계입니다.

swift
class MyReactor: Reactor {
    enum Mutation {
        case setLoading(Bool)
        case updateText(String)
    }

    // ... other code
}

State

State는 화면에 반영될 최종 상태를 나타내는 구조체입니다. Reactor는 지속적으로 State를 관리하고 업데이트하여 화면과 상호작용합니다.

swift
struct State {
    var isLoading: Bool = false
    var text: String = ""
}

ReactorKit의 실사용 예제

완전한 예제를 통해 ReactorKit의 사용법을 복습해보겠습니다. 이 예제에서는 버튼 클릭 시 API 호출을 시도하고, 결과를 화면에 표시하는 간단한 기능을 구현합니다.

swift
import UIKit
import ReactorKit
import RxSwift
import RxCocoa

class ViewController: UIViewController, View {
    var disposeBag = DisposeBag()
    let button = UIButton()
    let resultLabel = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(button)
        self.view.addSubview(resultLabel)
        self.button.setTitle("Fetch Data", for: .normal)
    }

    func bind(reactor: MyReactor) {
        // Action
        button.rx.tap
            .map { Reactor.Action.doSomething }
            .bind(to: reactor.action)
            .disposed(by: disposeBag)

        // State
        reactor.state
            .map { $0.result }
            .bind(to: resultLabel.rx.text)
            .disposed(by: disposeBag)
    }
}

이 코드는 button이 클릭될 때 doSomething이라는 Action을 트리거하고, resultLabel에는 state.result가 업데이트될 때마다 텍스트를 변경합니다.

ReactorKit는 Swift로 구현된 애플리케이션에서 비즈니스 로직을 명확하게 관리할 수 있게 해줍니다. 이번 글에서는 ReactorKit의 주요 컴포넌트인 Reactor, Action, Mutation에 대해 설명했습니다. 이를 통해 더 깔끔하고 유지보수하기 쉬운 코드를 작성할 수 있기를 바랍니다.