How to send an action with a closure as a parameter

In order to start implementing TCA in our large code base, I would like to do something like this:

func doThis(callback: @escaping () -> Void) {
    viewStore.send(.someAction(callback))
}

But unfortunately, having an action with a callback as a parameter makes the Action enum unable to conform to Equatable.

1 Like

I would like to have more context, but my gut tells me you want callback to be part of some dependency in environment, not Action. Also, you don't really need equateability on Action unless you're writing tests for the reducer.

We thought about putting the callback in the environment, but it has to be provided by the caller of the function and therefore will not be known at the time of creating the environment.

If you really need to do this - and I think there are valid use cases for doing this - then wrap your closure in a type and provide your own implementation of equatable on that type. This could be as simple as having a UUID on that type and using that for equality.

1 Like

I think @lukeredpath's answer is probably best for a quick fix and directly getting what you want, but I would also agree that more context would be needed to give an optimal answer. I think that for the most consistent codebase it really would be best to move this sort of stuff directly into reducers and environments.

In my experience with this architecture, views are best limited to 1. rendering the view based on the state and 2. sending actions to the store. So any unit of work that needs to run should really be wrapped in an effect that feeds back into the reducer, and then the views can re-render themselves based on any changes to the state.

If it's UIKit code, this is definitely not the "usual" way things are done, where state tends to be kinda littered throughout the code. But this sort of approach can really aid in modularity & testability.