From 1b476210bad060c338da1b95ca8cd768f92b55f3 Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Fri, 14 Mar 2025 12:18:04 -0700 Subject: [PATCH 1/4] Add initial action to `Store.init` It is common to send an action to a store when it is first created to kick off some long-living effects. While many utilize the `onAppear` view modifier for this work, we can simplify things by making the store's initializer a little more powerful. --- Sources/ComposableArchitecture/Store.swift | 7 ++++++- Tests/ComposableArchitectureTests/StoreTests.swift | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Sources/ComposableArchitecture/Store.swift b/Sources/ComposableArchitecture/Store.swift index 397a8ea9307b..dbf54119befd 100644 --- a/Sources/ComposableArchitecture/Store.swift +++ b/Sources/ComposableArchitecture/Store.swift @@ -159,11 +159,13 @@ public final class Store { /// /// - Parameters: /// - initialState: The state to start the application in. + /// - initialAction: An action to send the store when it is created. /// - reducer: The reducer that powers the business logic of the application. /// - prepareDependencies: A closure that can be used to override dependencies that will be accessed /// by the reducer. public convenience init>( - initialState: @autoclosure () -> R.State, + initialState: @autoclosure () -> State, + initialAction: @autoclosure () -> Action? = nil, @ReducerBuilder reducer: () -> R, withDependencies prepareDependencies: ((inout DependencyValues) -> Void)? = nil ) { @@ -175,6 +177,9 @@ public final class Store { initialState: initialState, reducer: reducer.dependency(\.self, dependencies) ) + if let initialAction = initialAction() { + send(initialAction) + } } init() { diff --git a/Tests/ComposableArchitectureTests/StoreTests.swift b/Tests/ComposableArchitectureTests/StoreTests.swift index 5d0c4a04418e..406191845efc 100644 --- a/Tests/ComposableArchitectureTests/StoreTests.swift +++ b/Tests/ComposableArchitectureTests/StoreTests.swift @@ -1213,6 +1213,17 @@ final class StoreTests: BaseTCATestCase { } } } + + @MainActor + func testInitialAction() async { + let store = Store(initialState: 0, initialAction: ()) { + Reduce { state, _ in + state += 1 + return .none + } + } + XCTAssertEqual(store.currentState, 1) + } } #if canImport(Testing) From 1a6c97103b7e175a9dde692102de48a8399a24ee Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Fri, 14 Mar 2025 12:46:08 -0700 Subject: [PATCH 2/4] wip --- Sources/ComposableArchitecture/Store.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/ComposableArchitecture/Store.swift b/Sources/ComposableArchitecture/Store.swift index dbf54119befd..ea2b2f9e6778 100644 --- a/Sources/ComposableArchitecture/Store.swift +++ b/Sources/ComposableArchitecture/Store.swift @@ -164,8 +164,8 @@ public final class Store { /// - prepareDependencies: A closure that can be used to override dependencies that will be accessed /// by the reducer. public convenience init>( - initialState: @autoclosure () -> State, - initialAction: @autoclosure () -> Action? = nil, + initialState: @autoclosure () -> R.State, + initialAction: @autoclosure () -> R.Action? = nil, @ReducerBuilder reducer: () -> R, withDependencies prepareDependencies: ((inout DependencyValues) -> Void)? = nil ) { From b86e6013335e02dbf42a4416a59d065276aacbd3 Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Fri, 14 Mar 2025 12:54:33 -0700 Subject: [PATCH 3/4] wip --- Tests/ComposableArchitectureTests/StoreTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/ComposableArchitectureTests/StoreTests.swift b/Tests/ComposableArchitectureTests/StoreTests.swift index 406191845efc..14df3b53b434 100644 --- a/Tests/ComposableArchitectureTests/StoreTests.swift +++ b/Tests/ComposableArchitectureTests/StoreTests.swift @@ -1216,8 +1216,8 @@ final class StoreTests: BaseTCATestCase { @MainActor func testInitialAction() async { - let store = Store(initialState: 0, initialAction: ()) { - Reduce { state, _ in + let store = Store(initialState: 0, initialAction: ()) { + Reduce { state, _ in state += 1 return .none } From a3ed02df5c0234a7ba9e4671a1000281dd17bb61 Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Wed, 26 Mar 2025 15:56:30 -0700 Subject: [PATCH 4/4] wip --- .github/workflows/ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 637b5a7a87e1..ceedeba3e615 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,8 @@ jobs: - uses: actions/checkout@v4 - name: Select Xcode ${{ matrix.xcode }} run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode }}.app + - name: Update xcbeautify + run: brew upgrade xcbeautify - name: List available devices run: xcrun simctl list devices available - name: Cache derived data @@ -65,6 +67,8 @@ jobs: - uses: actions/checkout@v4 - name: Select Xcode ${{ matrix.xcode }} run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode }}.app + - name: Update xcbeautify + run: brew upgrade xcbeautify - name: Install visionOS runtime if: matrix.platform == 'visionOS' run: | @@ -100,6 +104,8 @@ jobs: - uses: actions/checkout@v4 - name: Select Xcode 15.4 run: sudo xcode-select -s /Applications/Xcode_15.4.app + - name: Update xcbeautify + run: brew upgrade xcbeautify - name: Build for library evolution run: make build-for-library-evolution @@ -118,6 +124,8 @@ jobs: deriveddata-examples- - name: Select Xcode 16 run: sudo xcode-select -s /Applications/Xcode_16.2.app + - name: Update xcbeautify + run: brew upgrade xcbeautify - name: Set IgnoreFileSystemDeviceInodeChanges flag run: defaults write com.apple.dt.XCBuild IgnoreFileSystemDeviceInodeChanges -bool YES - name: Update mtime for incremental builds