Functional SwiftUI with Redux

Liviu Coman
3 min readAug 10, 2019

--

In a previous article on Redux in Swift we saw how we can build a really basic counter app using SwiftUI and Redux, from scratch.

Here’s the UI code we ended up with:

SwiftUI and Redux work really well together and the benefits are immediate: the declarative syntax helps with readability and the strict unidirectional data flow makes code easier to test and reason about.

However, SwiftUI is still new and everyone’s still exploring different ways of using it to change their codebases for the better.

Thomas Ricouard has a more nuanced and advanced take on SwiftUI and DJ Mitchell has a really interesting approach to view models as functions.

Learning from each of them inspired me to look at my initial design and improve on it.

The first problem I wanted to solve is there’s a lot of boilerplate involved. Each view needs a reference to the Store and a props variable. This both decreases the signal-to-noise ratio in the codebase and distracts from the main responsibilities I think a view should have: rendering and handling user interactions.

The second problem I wanted to solve is the view is tightly coupled with Redux. Ideally I’d want the views to be agnostic of any business layer details in order to achieve a higher level of decoupling.

Reducing boilerplate

To get rid of boilerplate I took a step back and removed the Store from the CounterView, reverted it to its bare minimum and removed any functionality it might’ve had, with the assumption that I’ll add it back later.

I still wanted all potential views to get updated by the Store, so I created a special type of view that wraps the Store as an EnvironmentObject rather than the initial ObjectBinding and called it ConnectedView.

Then I placed the ConnectedView at the topmost layer in the view hierarchy of the SceneDelegate. In this way all children of ConnectedView will be automatically updated by the Store.

Finally, the initial CounterView didn’t really have a reason to be a struct anymore so I converted it to a free function:

Amazingly, the SceneDelegate from above remains exactly the same.

Adding back functionality whilst retaining decoupling

Here is where it gets interesting. I took the initial “props” parameter — which was just an integer value — and converted it to a series of functions that either return a value or promise to perform some action. To group this functionality together I defined it as a new type:

Here the type-alias acts as a protocol. It defines how an abstract “CounterProps” entity should look like but omits any implementation details. This keeps in line with the Inversion of Dependency principle of SOLID.

Now what remains is to plug CounterProps in CounterView:

A CounterProps implementation that makes use of the Store looks like this:

Which is just ready to be plugged in the view at SceneDelegate level to complete the mission:

Finally here’s the full final design so you can compare it with the initial one.

It’s split into the files or domains each entity would logically fit into.

Conclusions

The initial design is definitely shorter and to the point. You might find that that’s what works best for you.

The final design however improves on it by getting rid of a lot of boilerplate down the line as well as decoupling the views from the business logic. The advantage of that is that if you ever want to move towards Elm or MVVM or any other pattern, you’d be able to do so without affecting the UI layer. Which in the end leads to a less fragile and more resilient system.

This article is one of a multi-part series exploring State, UI and Redux and how we can leverage knowledge of these topics to write more modular and testable code in both iOS and Android.

--

--

Liviu Coman

Enthusiast of all things mobile and functional. Building a safer internet for kids as Engineering Lead @SuperAwesome.