We developed our React Native stack because we’re constantly trying to find tools that will make our products better. Any time we hear about a new tool or technique, our mobile team has a process for testing them out. If it proves out – delivering value to our clients — we’re quick to work it into our stack.
That’s how we ended up using React Native in the first place. One of our clients needed a cross-platform solution, and we had tested the other frameworks out there and found them lacking. So we tried React Native for Android, and it worked surprisingly well. Over the next year or so, we continued to build React Native apps, testing its limits and potential.
Today, React Native is our primary framework. We still do native Android and native iOS development in Java and Swift respectively, but most of the time in the battle of React Native vs. Swift, React Native can just deliver more. Here are all the tools we’re using for apps built with React Native — and all the tools we tested but didn’t choose. Want the quick version?
React Native vs. Ionic vs. Flutter
We tested so many frameworks for building cross-platform apps, because it always seemed like the perfect solution for clients who needed both iOS and Android apps. Facebook’s React Native has proven by far the best. Getting started with React Native was much simpler than the others, because it’s based on the React web framework, which is popular among frontend web developers. That’s made it possible for some of our frontend devs to learn React Native on the job, without needing a bunch of training and tutorials ahead of time.
Since it came out a few years ago, the framework has only gotten better, maturing rapidly and developing a thriving open-source community to support it. It’s incredibly flexible and quick to develop with, and if it doesn’t support a native feature, it’s very easy to incorporate native iOS or Android code into the project. Switching to a mostly React-based stack happened naturally, because it was so much easier and better to develop with than other options.
A big part of what makes React Native so useful is the full ecosystem of tools and extensions. Some of our mainstays:
The tools in our React Native stack
Storybook: A wonderful tool for browsing all the discrete view components within an app — and their various states. This is fantastically useful when we’re building new views. Instead of tinkering with the entire app ecosystem, we can just focus on the view in isolation and feed in whatever data we need to test the UI. So if we’re testing a particularly rare bug, we don’t have to try and replicate it, we can just trigger it and build a solution. Even better, we can combine this tool with storyshots to automatically generate UI snapshot tests, so we’re building the view and writing its tests at the same time.
Jest: This is the standard automated test framework that ships with React Native, and we’ve fallen in love with it. It has the rspec-inspired, easy-to-read syntax shared by most testing frameworks, of course, but it also makes mocking an absolute breeze, and it contains an incredible code coverage tool that even builds a neatly-formatted website developers can use to review gaps in their tests.
Thanks to these tools, we have far fewer UI bugs than we ever did with earlier methods of updating an app’s UI state.
Redux and redux-saga: Together, these development patterns allow us to elegantly manage a one-way flow of data through the entire app, including during asynchronous operations. This fits neatly with the reactive pattern that React Native is built upon. When data updates, the relevant views update. It’s as simple as that. Thanks to these tools, we have far fewer UI bugs than we ever did with earlier methods of updating an app’s UI state.
A mobile stack optimized for React Native source code
We also use plenty of tools that aren’t specific to React Native. Some of them are carryovers from iOS and Android development, others are framework agnostic.
Lookback: This is a centralized hub for the recordings from all the user tests that go into building an app. It lets us add notes to videos in real time, so it’s easier to recall important insights. Lookback is also a great tool for remote testing, because it lets the interviewer turn on the camera on the user’s device. That way we can record them in their environment as they engage with the prototype. The Lookback team is also constantly improving the software, so it just keeps getting better.
Otherwise known as a UX designer’s best friend.
Invision: Otherwise known as a UX designer’s best friend. Not only does it allow us to upload screens for testing mobile and desktop views, it has an intuitive commenting system that tightens the feedback loop for changes and improvements. Invision also comes with a mobile app — way better for approximating the native experience than browser-based simulators. To top it all off, Invision syncs with Sketch, our design tool of choice, and works with Lookback.
Jest code coverage: Jest comes packaged with Istanbul, which analyzes our full codebase and produces a detailed report of its test coverage. It even generates a local webpage that allows us to navigate through all our code and see highlights on the specific lines where coverage is missing.
It takes a lot of the thinking out of writing tests, cutting the time in half.
Snapshot testing: We’re also using Jest’s snapshot testing feature to simplify the process of writing tests. Using snapshots allows us to set up a particular condition and save a snapshot of the state of the app, rather than having to exhaustively write out what we expect to occur. Since our larger apps have hundreds of individual tests, this saves a lot of time in the long run.
Now, all we do is write an automated test for our code, and Jest runs the code with the data we provide. We expect to get a certain result, like a function that takes a date and gives it back to us in a certain format. Traditionally, we’d have to run data into the app to test it, and then test that the result matches what we expect — a whole separate set of code to parse the data and make sure it’s correct. A Snapshot test takes an image of the result, matches it to the image it expects to see, and determines if the two match. If it doesn’t, the test will fail. It takes a lot of the thinking out of writing tests, cutting the time in half.
Linting: We started using this process as something of an experiment, but it's become a pretty reliable part of how we work. Our code editing workflow has robust support for automatic linting and code formatting using eslint and prettier. Es-lint has a built in “fix” flag, which attempts to automatically solve errors. It's saving us a lot of time on PR reviews, because we don’t have to worry about small style fixes. It also lets us sync configuration files for each project, so we can change formatting rules as needed.
Codecov: This has been useful to us in the past, and we're starting to use it again on specific projects thanks to its easy integration with GitHub. Codecov is a code coverage tool that provides us with a “sniff test” to go alongside our peer review process. If there’s code being merged in that isn’t being tested and might cause problems, Codecov gives us a much better chance of catching it.
We found that this made our code a lot denser and harder to read without providing much value in return.
Bitrise: A great tool to use for continuous integration. This builds and tests the app any time code is merged in, so we can keep getting new builds out to our customers on a regular basis. Best of all, we don’t even have to flip the switch to send out builds — Github integration takes care of everything. Our Bitrise stack automatically runs tests every time a PR is opened, sends out builds to beta testers every time we merge to develop, and resubmits the app to iOS and Android app stores when we merge to master. Basically it makes sure all the code that’s out there is exactly what we want.
It takes care of all the fiddly steps between finishing the code and seeing the app on phones.
Fastlane: Fastlane is basically Bactine-level for solving development pain. It takes care of all the fiddly steps between finishing the code and seeing the app on phones. The combination of Bitrise and Fastlane builds, tests and deploys our apps, with significant time savings. Because Fastlane is actually a bundle of discrete tools that handle the different aspects of building and deploying, it’s completely customizable. One of our favorite bundled tools is match, which completely automates the process of creating, downloading and linking Apple provisioning profiles — previously one of the biggest headaches in iOS development.
Fabric Beta Deployment: An awesome suite of tools. We currently use it for beta deployment, user metrics and crash reporting. Fabric addresses crashes in both beta builds and live versions of the app, and tracks user metrics like devices being used, daily users, retention, etc. It gives us a thorough look at the app’s performance and how it’s being used in real life.
Bitrise’s own build steps and custom workflows. We used these initially but found that making our own Fastlane script more robust was a more flexible solution that kept us platform independent. We are also able to build and distribute the app locally if need be, which allows for quicker troubleshooting if we run into problems.
It’s an awesome tool, but it has to run on macOS machines.
BuildKite: This is a very simple tool that allows us to manage our CI, but does none of the actual hosting — we take care of that on our own. The result is much faster than Bitrise — a build might take two minutes instead of twelve — and much more customizable. It’s an awesome tool, but it has to run on macOS machines. Right now we’re trying to see if we can set up inexpensive macOS machines to run it. If we can, we’ll be swapping this into our React Native stack.
Testflight: We used to use this, but when Apple bought the app, they locked down the number of internal testers to 25. You also have to pass Apple’s full review process to send the app to external testers, meaning you basically need to have a finished app before you can test. Fabric lets us test with a greater number of people while we’re still building, and it works for both iOS and Android.
Fabric Answers (for beta): This is an awesome suite of tools. We currently use it for beta deployment, user metrics and crash reporting. Fabric addresses crashes in both beta builds and live versions of the app, and tracks user metrics like devices being used, daily users, retention, etc. It gives us a thorough look at the app’s performance and how it’s being used in real life.
App Annie: This is another analytics tool we love, and it makes a great supplement to Fabric’s Answers. It offers a lot of the same functionality, but also compares your app data to that of your colleagues and competitors in the App Store — offering much more granular information than Apple itself does.
The tool was useful, but we discovered a memory leak in their code that caused one of our apps to crash
Sentry: We still use Sentry for crash reporting, but we had to remove its more granular logging component that tracked users as they moved through the app. The tool was useful, but we discovered a memory leak in their code that caused one of our apps to crash, so we’ve disabled it for the time being pending a fix.
Google Analytics: This is a great tool from a business and marketing perspective, but it’s less helpful for collecting the technical metrics that drive how we update and maintain our code. We’re happy to put it in for a client that’s interested, but Fabric gives us a set of information that’s better for our needs as developers, like reports on crashes and tech being used, among other things.
Fabric’s Crashlytics: An awesome suite of tools. We currently use it for beta deployment, user metrics and crash reporting. Fabric addresses crashes in both beta builds and live versions of the app, and tracks user metrics like devices being used, daily users, retention, etc. It gives us a thorough look at the app’s performance and how it’s being used in real life.
This makes fixing problems much more efficient.
Sentry: While Sentry isn’t great for analytics right now, we still use its crash-reporting suite because it’s built around a feature that lets users actually report what they were doing when the crash occurred. This takes a lot of the guesswork out of production issues and makes fixing problems much more efficient. It also has an extensive set of issue tracking tools that rival the other solutions we’ve used.
We’ll keep updating this list as we continue testing and improving our React Native app stack. Want a quick reference? Download our quick guide to React Native tools.