Making Tucci: The Technical Details
React Native, Redux, Parse, and More
I made an iOS app called Tucci, which helps you find rare restaurant reservations. I made it to get some practice making products, but I learned also learned some new technical tricks along the way.
If you’re making mobile apps, you might find this useful — or hey, just a fun read. For more reading on Tucci and why we made it, check the first article:
React Native
Tucci is built with React Native, which I also use at work in a hybrid app of UIKit, React Native, and good ol’ web views. On the other hand, Tucci is a vanilla React Native app built with the exact commands you find in the documentation. Because the whole thing is in React Native, I ran into some new problems that I haven’t in my day-to-day work.
Navigator
I finally used Navigator, which had long been on my “experiment with this” list. Navigator is an entirely React-based implementation of the mobile navigation “screen”/“page” paradigm. It’s often compared to NavigatorIOS, an implementation of navigation using iOS’s native navigation controller.
NavigatorIOS gives you the exact behavior as vanilla UIKit apps but has some limits due to its inherent abstraction — for example, it’s currently impossible to customize the bar button items with other React components.
Experienced iOS developers will bemoan the duplication of UIKit work with the React-based Navigator, such has dealing with how to size the navigation bar buttons or replicating the transition animation. I agree that it is unfortunate, but having to re-implement interactions is strictly better than relying on an abstraction that will inevitably fail and frustrate you.
Performance
Dropping frames on a mobile app is jarring — users have been conditioned by the smooth performance of the default apps to expect a high frame rate and buttery gestures.
The most common cause of dropped frames in Tucci is changing some state of the app while the user is interacting, such as swiping between the “By Date” and “By Restaurant” list views. Changing state often causes React to try to re-render parts of the app, which takes CPU cycles away from the interaction and animation logic to re-render parts of the app that may not have actually changed.
I think using immutable objects will be especially critical for performant React Native apps. I’m still not convinced that you could make something as gesture-heavy and fluid as Paper at this point in time, but most apps should be just fine.
For more on my experiences with React Native, check out React Native In Production:
Redux
Redux has been making waves in the React community and was on my list of new treats to sample. There’s lots of writing about Redux, including some very good bits on the Redux website. The entire state of Tucci is stored in this shape of object:
The Redux spin on unidirectional data flow makes React apps even easier to reason about than Flux. Having written some medium-sized Flux apps, I definitely prefer having All The State collocated instead of distributed across many stores. At the same time, I don’t think there’s a pressing urge to migrate my existing Flux apps to Redux, but green-field projects should definitely check it out.
I’ve also been experimenting with Relay, which will probably supersede both Flux and Redux for some folks. The relatively small scope of Tucci (one client, small API surface area) made implementing a GraphQL server feel like overkill, but I’m sold on the benefits of Relay for larger projects. Check my introduction to Relay for a full example:
Middleware
One side-effect of having all of your state in one place is that you can inject “middleware" to observe changes in the state.
With Tucci, I created a simple analytics middleware that would log important events to Amplitude. It was so much easier to have all of this logging code in one place, instead of playing whack-a-mole throughout the components as various bits of state change. It looks something like this:
Under the hood, that Analytics object shims out to a native module which invokes the Amplitude SDK.
Parse Cloud Code And Webpack
Parse is an indispensable entry in every hacker’s tool belt. Cloud Code, which hosts JavaScript RPC endpoints and runs background jobs, forms the communication channel between the app, the backend, and HackerTable.
Although you write Cloud Code in JavaScript, it’s not a normal environment: Parse provides their own HTTP library, their own Promise implementation, an undocumented amount of support for ES6, and you can’t “require” NPM packages as you would in normal Node code. This isn’t a knock against Parse and I totally understand the constraints, but I wanted to keep my workflow as normalized as possible across the React Native and Parse files.
As a hack, I opted to Webpack my Cloud Code. This let me write a known variant of ES6 and seamlessly require npm modules like Moment. There’s nothing special you have to do to make Webpack work against Parse, this is my Webpack config:
Note that it outputs to “cloud/main.js”, which is where Parse will look to initialize your Cloud Code.
Next
I had a lot of fun hacking on these tools with Tucci. Tech aside, I’ve already heard from folks who made reservations with Tucci, which is pretty neat. I don’t see the app or toolset changing drastically in the future, which might be a testament to the solid foundation of React Native and Redux.
If you thought this was interesting or helpful, follow me @clayallsopp for future writing :)