Shared State: The Solution, Part 1

Episode #269 • Mar 4, 2024 • Subscriber-Only

The various approaches of sharing state in the Composable Architecture are mixed bag of trade offs and problems. Is there a better way? We’ll take a controversial approach: we will introduce a reference type into our state, typically a value type, and see what happens, and take it for a spin in an all new, flow-based case study.

The Solution, Part 1
Introduction
00:05
Shared state as a reference?
02:12
Improving the ergonomics of shared state
11:06
Complex flow case study
25:48
Next time: Adding another step to the flow
39:05

Unlock This Episode

Our Free plan includes 1 subscriber-only episode of your choice, plus weekly updates from our newsletter.

Introduction

Brandon: We have now seen two approaches to sharing state in a Composable Architecture application:

You can model everything as value types directly in your features’ states, but then you are left with the difficult problem of keeping a bunch of disconnected values in sync. This most likely means a liberal dose of onChange reducers and/or delegate actions, and it will be quite easy to get wrong. And also your tests will suffer since you will need to assert on changes to all of those copies of state.

Stephen: Or you can model your shared state as a dependency, but it takes a bit of boilerplate to accomplish, and worst of all the state isn’t actually held in the feature’s State struct. It’s only held in the reducer, and so we have to introduce even more boilerplate to listen for changes in the shared state and play them to the feature’s state, just so that the view can get access to that state.

It feels like we’re playing whack-a-mole with shared state. Each attempt solves a problem and then a whole new problem pops up.

Brandon: However, there is something pretty interesting about the dependency style of shared state that sets it apart from the synchronization style. By using a dependency for our shared state we have in some sense introduced a reference type into our feature. After all, structs with closures are basically a crude approximation of reference types, which is what our UserSettingsClient type is. This means it behaves like a class for all intents and purposes.

In general, dependencies are very reference-y, and we are seeing the pros and cons of that fact very directly in isowords. The pros are that state can be updated from any place in the entire app and every other part of the app can see those changes immediately. That’s exactly what we want from shared settings state.

Stephen: But the cons are that there is a lot of setup needed to make the dependency work in state, and it made testing a pain. We had an extra onAppear and userSettingsUpdated action to deal with in order to communicate between the dependency and the feature.

So, whether we like it or not, the share state dependency has introduced a reference type in our feature, and if we are OK with that, then my next question would be: could we have just crammed a reference type directly into the feature’s state from the beginning? Wouldn’t that give us the state sharing capabilities without any of the boilerplate of a dependency?

Well, let’s try it out.

This episode is for subscribers only.

Subscribe to Point-Free

Access this episode, plus all past and future episodes when you become a subscriber.

See plans and pricing

Already a subscriber? Log in

Downloads