Could you introduce your app in a few sentences?
I work for a company called mycujoo. Our original aim was to target the “long tail” of football - those clubs, leagues, and federations who have historically been underserved in broadcasting - and provide them with a platform to stream their matches live. Each of these clubs can create their own TV and broadcast their games. To do that, they can use Cerevo, a dedicated streaming device, our Android app, or our iOS app. I built the iOS app, and a new version with all new UI and new functionality is awaiting release. (Now released.)
In simple terms, it is a camera app with recording and streaming functionality, which uses React Native for everything with the streaming part executed natively. The app is intended to be used by the rights holder such as a club or federation to stream to our servers, and then users can watch the games via our website. mycujoo has a presence in many countries and continents, and is particularly strong in Brazil and Asia, but we are developing quickly across the world and currently stream games from 67 different countries.
What made you decide to switch to React Native?
This app was started in React Native. I had native iOS experience before, but when React Native was out I was very intrigued. I started building little prototypes, and saw that it's a very nice and quick way to create a simple app. Then I found mycujoo and they wanted their app in RN, with the thinking that it might work to have the iOS and Android app with the same codebase, so I joined the company. As it turns out we kept the Android app separate, but I kept it in RN for iOS. I think it's a very nice way to work with apps, since it makes certain things much easier. Of course with every good thing that you get from RN, a bad thing comes along too.
One is the verbosity of RN when you need to interact with or change native parts.
Essentially, every time I need to make a new native module or a view, I need to create a JS interface for it, a .m bridge, the module itself in Swift, and then a manager to connect the bridged interface to the module.
It makes sense and it works, but it's sometimes a bit too much work for a small functionality that interacts with a native part, such as keeping the screen on and preventing the phone going to sleep. And when the component gets big it can get a bit too centralized, so if I have a stream manager, it ends up being huge, because otherwise I need more bridges and managers and so on.
Another one is the performance, even though it's very close, it's still not as performant as native. The difference is very small, but 98% of the speed is still not 100% of the speed.
Yet another issue is the whole JS universe, and its problems and benefits.
And of course there is the problem of native to native communication, which goes through the JS part of the application, so you pay the penalty more than you need to sometimes. I mean you can do it directly, but then that requires coupling things which you might not want to be coupled, so it’s a decision one has to make.
Still I'm happy with choosing React Native.
How did you transition to React Native
For this app I didn't have to transition, but I have thought of how I would go about transitioning the app from RN to native in the future if it was necessary, and it's not a happy thought.
I think transitioning from native to RN is possible in steps, but not the other way around.
As for me, it was an easy transition to go from native to RN in my app experience, since the experience I had with native was mostly me building things alone. I hadn't worked in a team making iOS apps yet. I was in a team doing macOS development. After working with that for a while, I got to know the Apple ecosystem structure and their logic, so iOS was the next step for me, the next technology to explore and play with.
After a couple of years, I discovered RN when it was open source, and I was very interested. When I tried out the demos, it was very exciting to see that things like buttons and text inputs could be drawn up so easily, and controlled even more easily.
Of course that's when your brain starts understanding that this is a whole new way to work with a state, so I needed to switch my thinking from the Apple way to the React way.
In the beginning, it was a bit strange and seemed very simple, in a bad way, to do state handling via setState, and then it’s complete. It seemed very primitive. But I tried to see how web developers did things with React, since it's the same logic.
Then I learned about Redux, and tried that for a bit. That seemed awesome too, and it reminded me of the way state is often handled in Clojure. Functions that control other functions, and then the state can be either not there, or in a centralized place with some functions to control it.
This felt good. Redux seemed like a nice way to do state management. Until now, I think it's one of the best ways to work with state. I am still learning new things with Redux.
But even Redux has its good and bad sides.
Redux is awesome to work and reason with. But it’s very verbose.
The Redux community is amazing, and does great things! Sagas, and offline and persist, and many others besides. But try to combine more than 2-3 of those, and good luck connecting the pieces and making them work together in a nice, performant and non-verbose way.
For example, I needed to do persistence with Redux, and it worked easily with redux-persist. Then I wanted to do more with it. I wanted some things to not persist. So I had redux blocks, for example, for settings of the app, some API work, some streaming state, and so on. Then I had to think how to separate the persisted block elements from the non-persisted.
I decided the best way to do that was to have keys whose names start with
_. Then I created a filter for when it was going to persist, which kept the
_s out. It worked well but it’s not the perfect solution.
I think the best thing about Redux is just the idea behind it, and the great ideas developed for and by the community.
I’ve looked for other ways to do state management, and only MobX was a possibility at one point, but I avoided using it since colleagues and web developers said it was fine for simple things, like for inside a component, but not when it's too many moving parts.
Recently, we started developing a new app at mycujoo, which is native with Swift and ReactiveX to replace state. It's a new way and I’m still learning, but it's pretty interesting. I might incorporate it later in the RN app too.
Have your tried other cross platform technologies before using React Native?
Very very briefly, I tried Xamarin. I found it didn’t work very well.
It was basically writing the Apple way, but just translated to C# from Objective-C
I haven't tried Ionic or other technologies, but I have used apps that were developed with them, and they didn’t work in the way I expected them to.
Essentially RN was the best option that could work as well as the native apps, and it shows since there are implementations at work for iOS, Android, Windows Phone, Windows, macOS. I wouldn't be surprised if I learned that there is an early stage implementation for Linux desktop or even Symbian or another platform.
I have tried RN for Mac. I was talking with ptmt when he started the fork, but I didn't actively participate for a long time. This partly was due to me having very little free time, and partly due to my limited experience. I did that before I started working with RN full time, so I was still learning. I'm sure I could do a much better job now, since he needs help to basically wrap all the native parts in JS. Maybe I should write to him and try to make a couple of PRs.
What has your experience been working with React Native in terms of app performance, have you noticed any impacts?
In terms of performance I’m very happy with the development experience, with hot reload, and so on. I’m mostly happy with the app performance. But there are times where it becomes problematic.
Most of the time, everything works fine, but there are times where you can feel the app going slower than it should. I might be at fault sometimes, with some silly bug while I am still developing, but its very quick to degrade the app performance and experience. With Swift and Objective-C, it's either working fast, or crashes, or it's an obvious slowdown. With RN, it's either working fast, or crashes, or obvious slowdown, or steady and slow performance degradation, to the point where after 15 minutes you ask "Why is my app so slow now? It's as fast as it was 5 seconds ago, but it's still slow, and I didn't notice it." Then you restart the app and it's fine.
It’s not a problem with RN specifically, but it's there.
Another issue is when large amounts of data have to cross the JS bridge, either for debugging or otherwise, or if something passes through that bridge many times, it's one more potential bottleneck to keep in mind and kind of optimise for. Sometimes you just want to not care about that stuff, and just write your app.
Two other issues I had are problems with rendering. I’ve had problems with double rendering or more, and sometimes it is easy to solve, with the debugger, but sometimes not. The
PureComponent was added at some stage, and the function components too, but even today they are still not a replacement, because they are not supported fully by some libs or even Facebook's own libs and RN. And the tools for RN are unfortunately not on the level of those for React.
The second issue is with third party dependencies. I use redux-form and react-native-debugger, and apparently the two don’t like each other.
If I try to debug my form screen, the app will suddenly go very slow.
And until now I haven't fixed it, there are issues open in redux, redux form, redux devtools and react native debugger, and no one has solved it yet.
So I've had to debug by turning redux devtools off and doing
console.log(). This works, but it's not perfect, and it was the only way I could have my app be usable while developing that screen.
Otherwise, the production builds are pretty fast. I don't feel any slowdown. If anything, it might be just my mind knowing what's behind and making it feel like it could be even better.
And of course everytime I use an app that I know is using RN, if I see any tiny bit of slowdown or lag or funky visual or anything out of the ordinary, I think to myself what could have caused this? Do I need to worry for my app? Do I need to fix something preemptively?
How has adopting React Native affected developer productivity?
For this app, my "team" was just me. Anytime I did some UI work, my productivity would feel better than usual. If I worked on an interesting functional part of the application, again my productivity would feel higher.
But debugging was when I felt it went down. Fighting with the rendering lifecycle, trying to do monthly or bi-monthly upgrades of dependencies would feel slow and that it took more time than it should.
After more than a year of working with this app, I feel like if I need to fix something, it will be done quickly. Basically, the times that I feel less productive than normal are when I wait for the bundler to finish, or when I try to debug some weird refresh/rendering/diffing problem, trying to fight with RN, until I end up making RN understand what I need it to do, or until I give up and change my program's logic to work around the problem in RN.
Which tools, libraries and frameworks are part of your development process with React Native?
Editor: VS Code
Debugger: react-native-debugger, and I think that's it.
I always have one window of VS Code open, fullscreen, then one terminal window with the bundler running in the background, and the react-native-debugger for console and redux and breakpoints.
On the iPhone I use for testing, I have this overlay button that iOS provides, and a tap on it causes a fake shake gesture, so I can reload and keep developing without needing to actually shake the device.
I try new things very often, for testing, bundling, dependencies, debugging etc.
If something feels complete or really helpful, it stays. If it doesn't, it just go back to "to be tested in 2 months" mode.
One more tool is fastlane. It's awesome for builds etc.
Fastlane is basically a nice way to script all the version bumps, builds for beta, internal, release etc, upload to App Store etc. It's very nice to work with locally, and for the CI tool to do it's job.
And I have made my own layout library that I use, to make a few things I need often, easier to work with.
What resource have you used to learn React Native? Books, tutorials, courses etc. Anything you can recommend?
The official doc is good. Besides that, the best things I have found are a couple of monthly newsletters for RN, such as reactnativecoach.com and reactnative.cc and the awesome-react-native repo on Github. Other than that, I just google React Native things every couple of weeks or so, and look at the commits on Github for the official repo and anything else that looks interesting, and try to learn more from those.
Anything else you would like to mention?
Just that I think that React Native is a great idea, with a very good implementation, big community, and is enjoyable to work with. It still has a way to go until it's perfect, and a lot of people including me are helping. We will get there, just keep it up, use it, develop it, and most importantly experiment with it. That's where most ideas originate from!