Adding withAnimation to button action result in compile error

                    Button {
                        withAnimation { // Conflicting arguments to generic parameter 'Result' ('Void' vs. 'StoreTask')
                            store.send(.decrementButtonTapped)
                        }
                    } label: {
                        Image(systemName: "minus")
                            .symbolVariant(.circle.fill)
                            .imageScale(.large)
                    }

How should I do this?

My code
import SwiftUI
import ComposableArchitecture

struct CounterFeature: Reducer {
    struct State: Equatable {
        var count = 0
        var numberFactAlert: String?
    }
    
    enum Action: Equatable {
      case decrementButtonTapped
      case incrementButtonTapped
    }

    
    func reduce(into state: inout State, action: Action) -> Effect<Action> {
      switch action {
      case .decrementButtonTapped:
        state.count -= 1
        return .none

      case .incrementButtonTapped:
        state.count += 1
        return .none
      }
    }
}


struct CounterView: View {
    
    
    let store: StoreOf<CounterFeature>
    
    var body: some View {
        WithViewStore(self.store, observe: { $0 }) { store in
            VStack {
                HStack(spacing: 50) {
                    Button {
                        store.send(.decrementButtonTapped)  // I want to put withAnimation { } here
                    } label: {
                        Image(systemName: "minus")
                            .symbolVariant(.circle.fill)
                            .imageScale(.large)
                    }
                    .buttonRepeatBehavior(.enabled)
                    .buttonStyle(.borderedProminent)

                    Text("\(store.count)")
                        .font(.largeTitle)
                        .foregroundColor(.cyan)
                        .frame(width: 80, height: 60)
                        .background {
                            RoundedRectangle(cornerRadius: 20, style: .continuous)
                                .strokeBorder(.red, lineWidth: 2)
                        }
                        .animation(.easeInOut, value: store.count)  // don't want to have this here
                        .contentTransition(.numericText(value: Double(store.count)))
                    
                    Button {
                        store.send(.incrementButtonTapped)
                    } label: {
                        Image(systemName: "plus")
                            .symbolVariant(.circle.fill)
                            .imageScale(.large)
                    }
                    .buttonRepeatBehavior(.enabled)
                    .buttonStyle(.borderedProminent)
                }
                
            }
        }
    }
}

#Preview {
    CounterView(
      store: Store(initialState: CounterFeature.State()) {
        CounterFeature()
      }
    )
}

There's a send overload you can use for animations: send(_:animation:).

1 Like

:pray:

Why withAnimation cause compile error?

Because it shares the result type of its parameter closure. You can make it return Void by assigning the result of send to _ or adding a plain return to the end of the closure.

1 Like

And it's worth noting that it happens in plain Swift too:

func foo() -> Int {1}
let b = Button {
  withAnimation {
    foo()  // 🛑 Conflicting arguments to generic parameter 'Result' ('Void' vs. 'Int')
  }
} label: {
  Text("")
}
1 Like