0Pricing
Swift Academy · 강의

상태, 액션, 리듀서

기능을 상태에 작용하는 순수 리듀서로 모델링합니다.

상태, 액션, 리듀서은(는) CoddyKit의 무료 Swift Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Swift Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Swift Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

Composable Architecture란 무엇인가

구성 가능한 아키텍처, 즉 TCA는 일관되고 검증 가능한 구조로 스위프트 앱을 만들기 위한 라이브러리입니다. 여기에는 세 가지 핵심 요소가 있습니다. 기능의 데이터를 설명하는 State, 발생할 수 있는 모든 이벤트를 설명하는 Action, 그리고 동작에 따라 상태를 변화시키는 Reducer입니다.

이 단방향 흐름 덕분에 기능의 동작을 예측하기 쉽고 검증하기도 쉽습니다.

import ComposableArchitecture

// State holds data, Action describes events,
// a Reducer turns (state, action) into the next state.

@Reducer 매크로

기능은 @Reducer 매크로가 주석을 지정한 유형으로 정의됩니다. 이 매크로는 지원 코드를 생성하고, 하나의 응집된 단위 안에서 State, Action, 리듀서 body를 함께 선언할 수 있게 합니다.

관례상 유형 이름은 기능 이름을 따르며, 예를 들어 CounterFeature처럼 지정합니다.

import ComposableArchitecture

@Reducer
struct CounterFeature {
    // State, Action, and body go here
}

State 정의하기

State는 일반적으로 기능에 필요한 모든 데이터를 담는 구조체입니다. @ObservableState를 지정하면 SwiftUI가 변경 사항을 정밀하게 관찰하고 영향을 받는 부분만 다시 렌더링할 수 있습니다.

상태는 최소한으로 유지하고 파생 값은 계산하여 단일 기준 데이터가 되도록 하세요.

import ComposableArchitecture

@Reducer
struct CounterFeature {
    @ObservableState
    struct State: Equatable {
        var count = 0
    }
}

Action 정의하기

Action은 기능이 처리할 수 있는 모든 이벤트를 나열하는 열거형입니다. 사용자 탭, 응답, 타이머 신호 등이 여기에 해당합니다. 각 케이스는 상태를 직접 변경하라는 명령이 아니라 발생한 일을 나타냅니다.

명확한 Action 이름을 사용하면 기능의 동작을 별도의 설명 없이도 파악할 수 있습니다.

import ComposableArchitecture

@Reducer
struct CounterFeature {
    @ObservableState
    struct State: Equatable { var count = 0 }

    enum Action {
        case incrementTapped
        case decrementTapped
    }
}

Reducer 본문

리듀서 로직은 body 계산 속성에 있으며, 이 속성은 일부 ReducerOf<Self>를 반환합니다. 내부에서는 변경 가능한 state와 들어온 action을 받는 클로저와 함께 Reduce를 사용합니다.

Action을 분기 처리하고 그에 맞게 상태를 변경합니다.

import ComposableArchitecture

@Reducer
struct CounterFeature {
    @ObservableState
    struct State: Equatable { var count = 0 }
    enum Action { case incrementTapped, decrementTapped }

    var body: some ReducerOf<Self> {
        Reduce { state, action in
            switch action {
            case .incrementTapped:
                state.count += 1
                return .none
            case .decrementTapped:
                state.count -= 1
                return .none
            }
        }
    }
}

이펙트 반환하기

리듀서의 각 분기는 Effect를 반환해야 합니다. .none을 반환한다는 것은 상태가 변경된 후 수행할 추가 비동기 작업이 없다는 뜻입니다.

네트워크 호출처럼 부수 작업이 필요할 때는 해당 작업을 실행하는 이펙트를 반환합니다. 이펙트는 이후 수업에서 자세히 살펴봅니다.

import ComposableArchitecture

// Every reducer branch returns an Effect.
// No side effect needed? Return .none.
// Need async work? Return an effect describing it.
Reduce { state, action in
    state.count += 1
    return .none
}

State 변경은 한곳에서 관리됩니다

TCA의 핵심 규칙은 리듀서만 상태를 변경하며, 상태 변경은 Action에 대한 응답으로만 이루어진다는 것입니다. 뷰는 상태를 직접 변경하지 않고 Action을 보냅니다.

변경을 처리하는 이 한곳의 중심 지점 덕분에 데이터 흐름을 쉽게 따라가고 검증할 수 있습니다.

import ComposableArchitecture

// Views send actions; the reducer mutates state.
// store.send(.incrementTapped)  ->  state.count += 1
// No direct state mutation outside the reducer.

State에서 사용자 입력 모델링하기

폼과 유사한 기능은 편집 가능한 필드를 State에 저장하고 변경을 위한 동작을 추가합니다. 속성에 바인딩을 지정하면 SwiftUI 컨트롤이 형식 안전한 방식으로 동작을 통해 해당 속성을 업데이트할 수 있습니다.

여기서는 한 기능이 텍스트 필드와 전환 스위치를 추적합니다.

import ComposableArchitecture

@Reducer
struct FormFeature {
    @ObservableState
    struct State: Equatable {
        var name = ""
        var isSubscribed = false
    }
    enum Action: BindableAction {
        case binding(BindingAction<State>)
    }
    var body: some ReducerOf<Self> {
        BindingReducer()
    }
}

연관 값이 있는 Action

Action은 연관 값을 사용하여 데이터를 전달할 수 있습니다. 이를 통해 불러온 항목이나 오류처럼 작업에서 돌아오는 결과를 모델링하고, 리듀서가 이를 상태에 저장하도록 할 수 있습니다.

여기서는 응답 동작이 가져온 숫자를 전달합니다.

import ComposableArchitecture

@Reducer
struct NumberFeature {
    @ObservableState
    struct State: Equatable { var value = 0 }
    enum Action {
        case reloadTapped
        case responseReceived(Int)
    }
    var body: some ReducerOf<Self> {
        Reduce { state, action in
            switch action {
            case .reloadTapped:
                return .none
            case let .responseReceived(value):
                state.value = value
                return .none
            }
        }
    }
}

Equatable State가 도움이 되는 이유

State가 Equatable을 준수하면 TCA가 상태가 실제로 변경되었는지 감지할 수 있으므로, 뷰를 정확하게 업데이트하고 모든 경우를 빠짐없이 검증할 수 있습니다. 작은 요구 사항이지만 효과는 큽니다.

저장된 속성이 이미 Equatable이므로 대부분의 상태 유형은 별도의 작업 없이 Equatable을 채택할 수 있습니다.

import ComposableArchitecture

@ObservableState
struct State: Equatable {
    var count = 0
    var title = ""
}
// Equatable enables change detection and test assertions.

완전한 기능의 구조

완성된 기능은 위에서 아래로 읽을 수 있습니다. 매크로, 관찰 가능한 상태, 동작 열거형, 리듀서 본문이 차례로 나옵니다. 기능에 관한 모든 내용이 하나의 유형 안에 있으므로 TCA의 기능을 조합하고 검토하기 쉽습니다.

이 일관된 구조는 앱의 모든 기능에서 반복됩니다.

import ComposableArchitecture

@Reducer
struct CounterFeature {
    @ObservableState
    struct State: Equatable { var count = 0 }
    enum Action { case incrementTapped, decrementTapped }
    var body: some ReducerOf<Self> {
        Reduce { state, action in
            switch action {
            case .incrementTapped: state.count += 1; return .none
            case .decrementTapped: state.count -= 1; return .none
            }
        }
    }
}

빠른 확인: 세 가지 구성 요소

TCA에서 State, Action, Reducer가 각각 어떤 역할을 하는지 떠올려 보세요.

복습: State, Action, Reducer

TCA 기능의 핵심을 배웠습니다:

  • @Reducer는 모든 내용을 한곳에 담은 기능 유형을 정의합니다.
  • 구조체에 지정한 @ObservableState는 기능의 데이터를 저장하고 정밀한 관찰을 가능하게 합니다.
  • Action 열거형은 연관 값과 함께 사용할 수 있는 모든 이벤트를 나열합니다.
  • 리듀서 body는 Reduce를 사용하여 상태를 변경하고 Effect를 반환하며, 부수 효과가 필요 없을 때는 .none을 반환합니다.
  • 상태는 리듀서만 변경하므로 데이터 흐름을 예측할 수 있습니다.

다음에는 이 기능을 Store를 사용하여 SwiftUI에 연결합니다.

import ComposableArchitecture

// Recap: @Reducer + State + Action + body(Reduce)
// One type, one source of truth, predictable updates.

자주 묻는 질문

“상태, 액션, 리듀서” 강의는 무료인가요?

네 — “상태, 액션, 리듀서” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Swift Academy 강의 전체를 잠금 해제할 수 있습니다. Swift Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“상태, 액션, 리듀서”에서 뭘 배우나요?

기능을 상태에 작용하는 순수 리듀서로 모델링합니다. 브라우저에서 직접 실행하는 실습 코드로 Swift Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Swift Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Swift Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.

“상태, 액션, 리듀서” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Swift Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Swift Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 상태, 액션, 리듀서
  2. Store와 SwiftUI 통합
  3. 이펙트와 의존성
  4. 기능 조합과 테스트
← Swift Academy(으)로 돌아가기