React Native, Native
Making your Swift app more React Nativey
I’m going to let you in on a dirty little secret. Sometimes I think longingly about React Native.
For those of us who decide React Native is not the way, what if we could get some of the features while still writing Swift? Today we’ll explore how we can have a reactive, declarative UI code and hot reload app data so we can save tons of testing time. Also, maybe we can do something to bypass the app store for updates even just a little?
Reactive, Declarative UI
React Native lets us write UI code that feels more like a description of what the UI should be, separated from the logic that configures and transforms all the data. We don’t have the fancy virtual DOM React does, but we can work around that.
Reactor is a small Swift library I wrote inspired by Elm, Redux, and the work on the excellent ReSwift by Benjamin Encz and others. See the documentation for a more in depth understanding of Reactor, but the basic model we’re working with is this:
In a nutshell, we have one state object with all of the application data nested inside of it. Each of our view controllers has an update function that knows how to take the state object and update its view. The view controllers subscribe to the Reactor, which notifies them whenever the state changes.
An example of this update function might look like:
All UI updates go in this function. This gives us one easy place to declare exactly how our UI reflects the app data. It will always stay up to date, reacting to the any state updates.
If this hasn’t all settled in yet, don’t worry. Going in depth here is beyond the scope of this article. Read the documentation and ping me on twitter with questions. And if you don’t like Reactor, ReSwift is terrific and the pattern is simple enough you can easily roll your own. The point is, if we store our application data in one data structure, we can have simple reactive, declarative UI code in Swift without React Native or a mind bending FRP library that may scare co-workers away (but make you sound super smart at dinner parties).
We cannot, due to Swift limitations, hot reload recompiled code. Bummer.
But, we did just talk about representing our application data as a struct. What if, hypothetically, we could serialize/deserialize our entire state into some format—say… JSON—save it to the file system, and then watch that file for updates? Then, hypothetically, we could edit that JSON file in our favorite text editor and our app would automatically update using our Reactor architecture.
Check out the example project to see how it’s done. But it’s pretty much exactly like you might imagine: our state is designed to serialize/deserialize using Marshal, and then we use the hook it all together with our architecture and the file watcher.
I think there’s a lot of potential here: recreate buggy states users report, testing UI without having to recompile, easy inspection of your apps current state… all kinds of fun stuff.
Bypassing the App Store
We’re quickly approaching the end of the known iOS universe.
As we’ve dicussed before, we can’t hot reload Swift code. We do know we can hot reload application data, however. So, what if we represented more of our UI as application data? Maybe we could write a few reusable components, and the data itself would tell us which UI component it wants to use. This is something that Spotify is doing, as demonstrated by John Sundell. Watch that video. Cool, cool stuff.
React Native takes some heat from the iOS community; probably a lot is undeserved from developers who haven’t tried it, but like all tools it comes with its own pros and cons.
Maybe those cons outweight the pros for you in your project. That doesn’t mean we shouldn’t covet the pros or try to figure out how we can apply the ideas amazing software developers in other areas to our own domain.