Swift Academy · 강의

Store와 SwiftUI 통합

TCA 스토어에서 뷰를 구동합니다.

레슨 2/413개 단계

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

저장소란 무엇인가

저장소는 기능의 상태를 보유하고 리듀서를 실행하는 실행 중 객체입니다. SwiftUI 뷰는 저장소를 관찰하여 상태를 읽고, 변경을 일으키기 위해 저장소에 동작을 보냅니다.

저장소는 순수한 리듀서 로직과 실제로 상호작용하는 사용자 인터페이스를 연결하는 다리입니다.

import ComposableArchitecture
import SwiftUI

// A Store holds State, runs the Reducer,
// and is observed by SwiftUI views.

StoreOf 형식 별칭

StoreOf<Feature>는 특정 기능의 상태 및 동작 유형에 맞게 지정된 저장소를 간편하게 나타내는 별칭입니다. 뷰는 일반적으로 이를 저장 속성으로 보유합니다.

따라서 카운터 뷰는 StoreOf<CounterFeature>를 저장합니다.

import ComposableArchitecture
import SwiftUI

struct CounterView: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        Text("Count: \(store.count)")
    }
}

저장소 만들기

Store 초기화 구문을 사용하여 저장소를 만들고, 초기 상태와 실행할 리듀서를 제공합니다. 이 작업은 일반적으로 앱 진입점 근처에서 한 번 수행합니다.

후행 클로저는 기능의 인스턴스를 반환합니다.

import ComposableArchitecture
import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            CounterView(
                store: Store(initialState: CounterFeature.State()) {
                    CounterFeature()
                }
            )
        }
    }
}

State 직접 읽기

최신 관찰 방식을 사용하면 뷰에서 store.count처럼 점 표기법으로 저장소의 상태를 바로 읽을 수 있습니다. 상태가 @ObservableState이므로 SwiftUI는 변경된 값에 의존하는 부분만 다시 렌더링합니다.

간단한 읽기에는 추가 래퍼가 필요하지 않습니다.

import ComposableArchitecture
import SwiftUI

struct CounterView: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        VStack {
            Text("Count: \(store.count)")
        }
    }
}

Action 보내기

상태를 변경하려면 뷰에서 store.send(.someAction)을 사용하여 동작을 보냅니다. 저장소는 동작을 리듀서에 전달하고, 리듀서는 상태를 변경하며 이펙트를 시작할 수도 있습니다.

여기서는 버튼이 증가 동작과 감소 동작을 보냅니다.

import ComposableArchitecture
import SwiftUI

struct CounterView: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        HStack {
            Button("-") { store.send(.decrementTapped) }
            Text("\(store.count)")
            Button("+") { store.send(.incrementTapped) }
        }
    }
}

저장소에서 바인딩 만들기

양방향 바인딩이 필요한 SwiftUI 컨트롤을 위해 TCA에서는 상태가 바인딩 가능한 동작을 사용할 때 저장소에서 Binding을 만들어낼 수 있습니다. 컨트롤은 바인딩 동작을 보내 상태를 업데이트합니다.

여기서는 TextField가 이름 필드에 바인딩됩니다.

import ComposableArchitecture
import SwiftUI

struct FormView: View {
    @Bindable var store: StoreOf<FormFeature>
    var body: some View {
        TextField("Name", text: $store.name)
    }
}

기존 WithViewStore

관찰 기능이 도입되기 전에는 뷰가 사용자 인터페이스를 WithViewStore로 감싸 상태를 읽고, 동작을 보낼 viewStore를 얻었습니다. 이전 코드에서 여전히 이 방식을 볼 수 있습니다.

observe 클로저는 뷰가 의존하는 상태를 선택합니다.

import ComposableArchitecture
import SwiftUI

struct LegacyCounter: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        WithViewStore(store, observe: { $0 }) { viewStore in
            Text("Count: \(viewStore.count)")
        }
    }
}

관찰할 항목 선택하기

기존 방식에서는 observe 클로저가 뷰에서 관찰하는 상태의 범위를 좁히므로 해당 값이 변경될 때만 다시 렌더링합니다. 전체 상태를 관찰하는 것이 가장 간단하고, 일부만 관찰하면 큰 뷰의 성능을 높일 수 있습니다.

최신 @ObservableState는 이 작업을 자동으로 처리하지만, 이전 코드를 읽을 때는 observe의 작동 방식을 이해하는 것이 도움이 됩니다.

import ComposableArchitecture
import SwiftUI

// Observe just the count to limit re-renders:
WithViewStore(store, observe: { $0.count }) { viewStore in
    Text("\(viewStore)")
}

데이터를 포함한 Action 보내기

연관 값을 담은 Action은 해당 값을 제공하여 보냅니다. 이렇게 하면 뷰가 리듀서에 필요한 사용자 입력을 전달할 수 있습니다.

여기서는 행을 선택할 때 선택한 식별자를 보냅니다.

import ComposableArchitecture
import SwiftUI

struct ListView: View {
    let store: StoreOf<ListFeature>
    var body: some View {
        Button("Pick 42") {
            store.send(.rowSelected(id: 42))
        }
    }
}

동작에 애니메이션 적용하기

보낸 동작에 애니메이션을 연결하면 그 결과로 발생하는 상태 변경이 애니메이션과 함께 표시됩니다. send에 animation 인수를 전달하면 됩니다.

이렇게 하면 애니메이션 관련 처리는 호출 위치에 두고 상태는 단순한 데이터로 유지할 수 있습니다.

import ComposableArchitecture
import SwiftUI

Button("Toggle") {
    store.send(.toggleTapped, animation: .default)
}

뷰 구성하기

완전한 TCA 뷰는 StoreOf를 보유하고, 점 표기법으로 상태를 읽으며, 컨트롤에서 동작을 보냅니다. 나머지 작업은 리듀서가 처리하므로 뷰를 간결하고 선언적으로 유지할 수 있습니다.

이러한 분리 덕분에 TCA 뷰를 읽고 미리 보기하기 쉽습니다.

import ComposableArchitecture
import SwiftUI

struct CounterView: View {
    let store: StoreOf<CounterFeature>
    var body: some View {
        VStack {
            Text("Count: \(store.count)")
            Button("Increment") { store.send(.incrementTapped) }
        }
    }
}

빠른 확인: 사용자 인터페이스 구동하기

SwiftUI 뷰가 TCA에서 상태 변경을 일으키는 방법을 떠올려 보세요.

복습: 저장소와 SwiftUI

기능을 SwiftUI에 연결했습니다:

  • StoreOf<Feature>는 상태를 보유하고 리듀서를 실행합니다.
  • 초기 상태와 기능 리듀서를 사용하여 저장소를 만듭니다.
  • 최신 관찰 방식을 사용하면 store.count처럼 점 표기법으로 상태를 읽을 수 있습니다.
  • 뷰는 store.send(.action)을 호출하여 상태를 변경하며, 필요한 경우 전달 값이나 애니메이션을 함께 지정할 수 있습니다.
  • 기존 코드에서는 기존 WithViewStore와 그 안의 observe 클로저를 볼 수 있습니다.

다음에는 리듀서에 부수 효과와 주입 가능한 의존성을 추가합니다.

import ComposableArchitecture
import SwiftUI

// Recap: StoreOf holds state, view reads with dot syntax,
// store.send(.action) drives every change.
무료로 시작

AI 튜터와 함께 Swift을(를) 배우세요 — 무료

브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.

코스
122
레슨
409

자주 묻는 질문

“Store와 SwiftUI 통합” 강의는 무료인가요?

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

“Store와 SwiftUI 통합”에서 뭘 배우나요?

TCA 스토어에서 뷰를 구동합니다. 브라우저에서 직접 실행하는 실습 코드로 Swift Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

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

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

“Store와 SwiftUI 통합” 강의는 얼마나 걸리나요?

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

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

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

이 강의의 모든 강의

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