From 3b065d21285156265d32f67bc26b89c1070f5860 Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Wed, 28 May 2025 12:50:11 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[#46]=20Store=20=ED=83=80=EC=9E=85=EC=9D=98?= =?UTF-8?q?=20=EC=A0=9C=EB=84=A4=EB=A6=AD=20=ED=91=9C=ED=98=84=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/ReducerKit/Sources/Reducer.swift | 2 +- Core/ReducerKit/Sources/Store.swift | 14 +++++--------- .../Sources/Feature/AddFolder/AddFolderView.swift | 2 +- Mark-In/Sources/Feature/AddLink/AddLinkView.swift | 2 +- Mark-In/Sources/Feature/Login/LoginView.swift | 10 +++++----- Mark-In/Sources/Feature/Main/LinkListView.swift | 2 +- Mark-In/Sources/Feature/Main/MainView.swift | 2 +- Mark-In/Sources/Feature/Main/SideBar.swift | 2 +- Mark-In/Sources/Feature/MyPage/MyPageView.swift | 2 +- 9 files changed, 17 insertions(+), 21 deletions(-) diff --git a/Core/ReducerKit/Sources/Reducer.swift b/Core/ReducerKit/Sources/Reducer.swift index d2dd043..7111708 100644 --- a/Core/ReducerKit/Sources/Reducer.swift +++ b/Core/ReducerKit/Sources/Reducer.swift @@ -8,7 +8,7 @@ import Foundation /// 액션에 따른 상태 변화 로직을 정의하기 위한 프로토콜 -public protocol Reducer { +public protocol Reducer { /// View에 표시될 데이터를 정의 associatedtype State diff --git a/Core/ReducerKit/Sources/Store.swift b/Core/ReducerKit/Sources/Store.swift index 8fc30dc..ceb554e 100644 --- a/Core/ReducerKit/Sources/Store.swift +++ b/Core/ReducerKit/Sources/Store.swift @@ -7,21 +7,17 @@ import Foundation -/// Store 타입을 좀 더 간편하게 정의(표현). -public typealias StoreOf = Store - /// Reducer를 실행하고 UI를 업데이트하는 상태 관리자 @MainActor @Observable -public final class Store { +public final class Store { + + public typealias State = R.State + public typealias Action = R.Action private(set) public var state: State private let reduce: (inout State, Action) -> Effect - // Store.State == Reducer.State, Store.Action == Reducer.Action - public init>( - initialState: State, - reducer: R - ) { + public init(initialState: State, reducer: R) { self.state = initialState self.reduce = reducer.reduce(into:action:) } diff --git a/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift b/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift index 77a7ca1..458de0c 100644 --- a/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift +++ b/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift @@ -12,7 +12,7 @@ import ReducerKit struct AddFolderView: View { @Environment(\.dismiss) private var dismiss - @State private var store: StoreOf = .init( + @State private var store: Store = .init( initialState: AddFolderReducer.State(), reducer: AddFolderReducer() ) diff --git a/Mark-In/Sources/Feature/AddLink/AddLinkView.swift b/Mark-In/Sources/Feature/AddLink/AddLinkView.swift index e2951fe..80c5f8f 100644 --- a/Mark-In/Sources/Feature/AddLink/AddLinkView.swift +++ b/Mark-In/Sources/Feature/AddLink/AddLinkView.swift @@ -12,7 +12,7 @@ import ReducerKit struct AddLinkView: View { @Environment(\.dismiss) var dismiss - @State private var store: StoreOf = .init( + @State private var store: Store = .init( initialState: AddLinkReducer.State(), reducer: AddLinkReducer() ) diff --git a/Mark-In/Sources/Feature/Login/LoginView.swift b/Mark-In/Sources/Feature/Login/LoginView.swift index c7fd2e4..adc4098 100644 --- a/Mark-In/Sources/Feature/Login/LoginView.swift +++ b/Mark-In/Sources/Feature/Login/LoginView.swift @@ -13,7 +13,7 @@ import ReducerKit import Util struct LoginView: View { - @State private var store: StoreOf = .init( + @State private var store: Store = .init( initialState: LoginReducer.State(), reducer: LoginReducer() ) @@ -50,9 +50,9 @@ struct LoginView: View { } private struct BodyView: View { - private let store: StoreOf + private let store: Store - init(store: StoreOf) { + init(store: Store) { self.store = store } @@ -100,9 +100,9 @@ private struct BodyView: View { private struct SignInButtonList: View { @Environment(\.authorizationController) private var authorizationController - private let store: StoreOf + private let store: Store - init(store: StoreOf) { + init(store: Store) { self.store = store } diff --git a/Mark-In/Sources/Feature/Main/LinkListView.swift b/Mark-In/Sources/Feature/Main/LinkListView.swift index b7d4e70..e94c70b 100644 --- a/Mark-In/Sources/Feature/Main/LinkListView.swift +++ b/Mark-In/Sources/Feature/Main/LinkListView.swift @@ -18,7 +18,7 @@ private enum ViewConstants { struct LinkListView: View { - let store: StoreOf + let store: Store private var links: [WebLink] { let totalLinks = store.state.links diff --git a/Mark-In/Sources/Feature/Main/MainView.swift b/Mark-In/Sources/Feature/Main/MainView.swift index e6db047..c3d7dc9 100644 --- a/Mark-In/Sources/Feature/Main/MainView.swift +++ b/Mark-In/Sources/Feature/Main/MainView.swift @@ -11,7 +11,7 @@ import DesignSystem import ReducerKit struct MainView: View { - @State private var store: StoreOf = .init( + @State private var store: Store = .init( initialState: MainReducer.State(), reducer: MainReducer() ) diff --git a/Mark-In/Sources/Feature/Main/SideBar.swift b/Mark-In/Sources/Feature/Main/SideBar.swift index 121f225..90a4ad5 100644 --- a/Mark-In/Sources/Feature/Main/SideBar.swift +++ b/Mark-In/Sources/Feature/Main/SideBar.swift @@ -11,7 +11,7 @@ import DesignSystem import ReducerKit struct SideBar: View { - let store: StoreOf + let store: Store var body: some View { VStack(alignment: .leading) { diff --git a/Mark-In/Sources/Feature/MyPage/MyPageView.swift b/Mark-In/Sources/Feature/MyPage/MyPageView.swift index 68d46f0..f62f658 100644 --- a/Mark-In/Sources/Feature/MyPage/MyPageView.swift +++ b/Mark-In/Sources/Feature/MyPage/MyPageView.swift @@ -15,7 +15,7 @@ private enum ViewConstants { } struct MyPageView: View { - @State private var store: StoreOf = .init( + @State private var store: Store = .init( initialState: MyPageReducer.State(), reducer: MyPageReducer() ) From 66715597228c51af9b75b61eee67b31f8764fef3 Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Wed, 28 May 2025 12:56:57 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[#46]=20Effect.run=20=ED=81=B4=EB=A1=9C?= =?UTF-8?q?=EC=A0=80=20=EB=B0=98=ED=99=98=20=ED=83=80=EC=9E=85=EC=9D=84=20?= =?UTF-8?q?=EC=98=B5=EC=85=94=EB=84=90=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/ReducerKit/Sources/Effect.swift | 2 +- Core/ReducerKit/Sources/Store.swift | 4 ++-- Mark-In/Sources/Feature/Login/LoginReducer.swift | 11 +++-------- Mark-In/Sources/Feature/Main/MainReducer.swift | 5 ----- Mark-In/Sources/Feature/MyPage/MyPageReducer.swift | 7 +------ 5 files changed, 7 insertions(+), 22 deletions(-) diff --git a/Core/ReducerKit/Sources/Effect.swift b/Core/ReducerKit/Sources/Effect.swift index 42ae5cb..dd5b5a6 100644 --- a/Core/ReducerKit/Sources/Effect.swift +++ b/Core/ReducerKit/Sources/Effect.swift @@ -13,5 +13,5 @@ public enum Effect { case none /// Side Effect를 처리하고, 새로운 Action을 반환 - case run(() async -> Action) + case run(() async -> Action?) } diff --git a/Core/ReducerKit/Sources/Store.swift b/Core/ReducerKit/Sources/Store.swift index ceb554e..cc78341 100644 --- a/Core/ReducerKit/Sources/Store.swift +++ b/Core/ReducerKit/Sources/Store.swift @@ -32,10 +32,10 @@ public final class Store { private func handleEffect(_ effect: Effect) { switch effect { case .none: - break + return case let .run(action): Task.detached { [weak self] in - let newAction = await action() + guard let newAction = await action() else { return } await self?.send(newAction) } } diff --git a/Mark-In/Sources/Feature/Login/LoginReducer.swift b/Mark-In/Sources/Feature/Login/LoginReducer.swift index 9eb2658..2882eb8 100644 --- a/Mark-In/Sources/Feature/Login/LoginReducer.swift +++ b/Mark-In/Sources/Feature/Login/LoginReducer.swift @@ -26,8 +26,6 @@ struct LoginReducer: Reducer { case googleLoginButtonTapped case signInError - - case empty } @Dependency private var signInUseCase: SignInUseCase @@ -45,13 +43,13 @@ struct LoginReducer: Reducer { /// 중간에 로그인을 취소하거나, 애플 로그인 인증 방식이 아닌 경우는 빈 액션 반환 /// (에러 상황은 아니기 때문에 어떠한 액션을 던질 필요가 없음) guard let result = try? await authController.performRequest(request), - case let .appleID(idCredential) = result else { return .empty } + case let .appleID(idCredential) = result else { return nil } let appleSignInInfo = AppleSignInInfo(nonce: nonce, idCredential: idCredential) do { try await self.signInUseCase.execute(using: appleSignInInfo) - return .empty + return nil } catch { return .signInError } @@ -71,7 +69,7 @@ struct LoginReducer: Reducer { let googleSignInInfo = GoogleSignInInfo(user: result.user) try await self.signInUseCase.execute(using: googleSignInInfo) - return .empty + return nil } catch { return .signInError } @@ -80,9 +78,6 @@ struct LoginReducer: Reducer { // TODO: 에러 처리 필요 case .signInError: return .none - - case .empty: - return .none } } } diff --git a/Mark-In/Sources/Feature/Main/MainReducer.swift b/Mark-In/Sources/Feature/Main/MainReducer.swift index 57b4901..379e5f8 100644 --- a/Mark-In/Sources/Feature/Main/MainReducer.swift +++ b/Mark-In/Sources/Feature/Main/MainReducer.swift @@ -34,8 +34,6 @@ struct MainReducer: Reducer { case didCreateFolder(Folder) case occuredError - - case empty } @Dependency private var fetchLinkListUseCase: FetchLinkListUseCase @@ -88,9 +86,6 @@ struct MainReducer: Reducer { // TODO: 에러 처리 로직 추가 case .occuredError: return .none - - case .empty: - return .none } } } diff --git a/Mark-In/Sources/Feature/MyPage/MyPageReducer.swift b/Mark-In/Sources/Feature/MyPage/MyPageReducer.swift index 2698f7f..6d061a0 100644 --- a/Mark-In/Sources/Feature/MyPage/MyPageReducer.swift +++ b/Mark-In/Sources/Feature/MyPage/MyPageReducer.swift @@ -23,8 +23,6 @@ struct MyPageReducer: Reducer { case withdrawalButtonTapped case didFailWithdrawal - - case empty } @Dependency private var signOutUseCase: SignOutUseCase @@ -41,7 +39,7 @@ struct MyPageReducer: Reducer { // TODO: 이후 Auth 모듈로 분리하면서 코드 리팩토링 예정 do { try await self.withdrawalUseCase.execute() - return .empty + return nil } catch { return .didFailWithdrawal } @@ -50,9 +48,6 @@ struct MyPageReducer: Reducer { // TODO: 회원탈퇴 실패에 대한 처리 필요 case .didFailWithdrawal: return .none - - case .empty: - return .none } } } From c9bf44da9951e738d5da816a8ae9b7d8b92efbc0 Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Tue, 3 Jun 2025 13:04:26 +0900 Subject: [PATCH 3/3] =?UTF-8?q?Revert=20"[#46]=20Effect.run=20=ED=81=B4?= =?UTF-8?q?=EB=A1=9C=EC=A0=80=20=EB=B0=98=ED=99=98=20=ED=83=80=EC=9E=85?= =?UTF-8?q?=EC=9D=84=20=EC=98=B5=EC=85=94=EB=84=90=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 66715597228c51af9b75b61eee67b31f8764fef3. --- Core/ReducerKit/Sources/Effect.swift | 2 +- Core/ReducerKit/Sources/Store.swift | 4 ++-- Mark-In/Sources/Feature/Login/LoginReducer.swift | 11 ++++++++--- Mark-In/Sources/Feature/Main/MainReducer.swift | 5 +++++ Mark-In/Sources/Feature/MyPage/MyPageReducer.swift | 7 ++++++- 5 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Core/ReducerKit/Sources/Effect.swift b/Core/ReducerKit/Sources/Effect.swift index dd5b5a6..42ae5cb 100644 --- a/Core/ReducerKit/Sources/Effect.swift +++ b/Core/ReducerKit/Sources/Effect.swift @@ -13,5 +13,5 @@ public enum Effect { case none /// Side Effect를 처리하고, 새로운 Action을 반환 - case run(() async -> Action?) + case run(() async -> Action) } diff --git a/Core/ReducerKit/Sources/Store.swift b/Core/ReducerKit/Sources/Store.swift index cc78341..ceb554e 100644 --- a/Core/ReducerKit/Sources/Store.swift +++ b/Core/ReducerKit/Sources/Store.swift @@ -32,10 +32,10 @@ public final class Store { private func handleEffect(_ effect: Effect) { switch effect { case .none: - return + break case let .run(action): Task.detached { [weak self] in - guard let newAction = await action() else { return } + let newAction = await action() await self?.send(newAction) } } diff --git a/Mark-In/Sources/Feature/Login/LoginReducer.swift b/Mark-In/Sources/Feature/Login/LoginReducer.swift index 2882eb8..9eb2658 100644 --- a/Mark-In/Sources/Feature/Login/LoginReducer.swift +++ b/Mark-In/Sources/Feature/Login/LoginReducer.swift @@ -26,6 +26,8 @@ struct LoginReducer: Reducer { case googleLoginButtonTapped case signInError + + case empty } @Dependency private var signInUseCase: SignInUseCase @@ -43,13 +45,13 @@ struct LoginReducer: Reducer { /// 중간에 로그인을 취소하거나, 애플 로그인 인증 방식이 아닌 경우는 빈 액션 반환 /// (에러 상황은 아니기 때문에 어떠한 액션을 던질 필요가 없음) guard let result = try? await authController.performRequest(request), - case let .appleID(idCredential) = result else { return nil } + case let .appleID(idCredential) = result else { return .empty } let appleSignInInfo = AppleSignInInfo(nonce: nonce, idCredential: idCredential) do { try await self.signInUseCase.execute(using: appleSignInInfo) - return nil + return .empty } catch { return .signInError } @@ -69,7 +71,7 @@ struct LoginReducer: Reducer { let googleSignInInfo = GoogleSignInInfo(user: result.user) try await self.signInUseCase.execute(using: googleSignInInfo) - return nil + return .empty } catch { return .signInError } @@ -78,6 +80,9 @@ struct LoginReducer: Reducer { // TODO: 에러 처리 필요 case .signInError: return .none + + case .empty: + return .none } } } diff --git a/Mark-In/Sources/Feature/Main/MainReducer.swift b/Mark-In/Sources/Feature/Main/MainReducer.swift index 379e5f8..57b4901 100644 --- a/Mark-In/Sources/Feature/Main/MainReducer.swift +++ b/Mark-In/Sources/Feature/Main/MainReducer.swift @@ -34,6 +34,8 @@ struct MainReducer: Reducer { case didCreateFolder(Folder) case occuredError + + case empty } @Dependency private var fetchLinkListUseCase: FetchLinkListUseCase @@ -86,6 +88,9 @@ struct MainReducer: Reducer { // TODO: 에러 처리 로직 추가 case .occuredError: return .none + + case .empty: + return .none } } } diff --git a/Mark-In/Sources/Feature/MyPage/MyPageReducer.swift b/Mark-In/Sources/Feature/MyPage/MyPageReducer.swift index 6d061a0..2698f7f 100644 --- a/Mark-In/Sources/Feature/MyPage/MyPageReducer.swift +++ b/Mark-In/Sources/Feature/MyPage/MyPageReducer.swift @@ -23,6 +23,8 @@ struct MyPageReducer: Reducer { case withdrawalButtonTapped case didFailWithdrawal + + case empty } @Dependency private var signOutUseCase: SignOutUseCase @@ -39,7 +41,7 @@ struct MyPageReducer: Reducer { // TODO: 이후 Auth 모듈로 분리하면서 코드 리팩토링 예정 do { try await self.withdrawalUseCase.execute() - return nil + return .empty } catch { return .didFailWithdrawal } @@ -48,6 +50,9 @@ struct MyPageReducer: Reducer { // TODO: 회원탈퇴 실패에 대한 처리 필요 case .didFailWithdrawal: return .none + + case .empty: + return .none } } }