This is the second part of a series on migrating existing native apps to React Native. Check out the first blog post if you want to know why we went for React Native and how we approached it.
To understand how React Native works on mobile, you first need to look at the virtual DOM (Document Object Model) that is used in both React and React Native. If you’ve ever done web development, you know how the DOM works in the browser. If not, you might be interested in reading up on it. In short: The DOM represents a page as nodes and objects. In plain React, the virtual DOM is an in-memory representation of the UI on top of the actual DOM. When a node or object changes, React will diff the virtual DOM and the actual DOM, and only update those nodes or objects that have changed. In React Native, there is no browser DOM. Instead, the virtual DOM is rendered into native iOS or Android views.
This is what sets React Native apart from other cross-platform solutions. Rendering native components significantly speeds up interaction with the app, and while this also introduces some complexities (sometimes you will need to create a custom UI component), for us, it was definitely a good trade-off.
EDIT FROM JANUARY 2019: the native feel of react-native-navigation didn’t make up for the amount of Android bugs, tight coupling with screen components, and non-declarative API. We migrated to react-navigation.
Of course, it’s not all sunshine and rainbows. While the language itself is getting better, it is still difficult to set up a good development environment. Because of the dynamic nature of the language, doing something as simple as renaming a variable can still be a challenge. Coming from Android, you might find JetBrains’ IntelliJ useful, because of its familiarity. Web developers tend to stick with editors like VSCode or Atom when they go to React Native. As long as the plugins are there to support what you need, you can use any editor you want.
Although ESlint can also check that a codebase adheres to a specific style guideline, we strongly believe that a code style should be enforced by a tool. Instead of debating over coding style, we use Prettier to format our code. It integrates with ESlint, so when hitting save in our editor the code is formatted and statically analyzed.
We started rebuilding the application in React Native without types. But as the application grew, it became clear that a static type checking tool like Flow or TypeScript would help us refactor and discover bugs. The more of the codebase we covered with types, the more bugs we uncovered.
TypeScript by Microsoft and Flow by Facebook are similar tools, providing gradual static typing capabilities, a similar syntax, and widespread usage.
For React Native, Flow was a natural choice. It integrates nicely with the build tool, and most third-party libraries already provide Flow types.
EDIT FROM JANUARY 2019: After TypeScript gained more momentum, we decided to give TypeScript another change. We migrated most of our projects to TypeScript and didn’t look back. The editor support and the library support is 👌
Storybook is a UI development environment for your UI components. With it, you can visualize different states of your UI components and develop them interactively.
If we were to dream up a productive setup for developing UI components and screens, it would:
- Work on components and screens in isolation without starting the entire application
- Be able to describe and quickly switch between components and screens in different states
- Support hot reloading when styles and markup changes
- Have multiple simulators and cross-platform devices connected and see them all update when updating the code
We are happy to see that Storybook delivers all of these. It is a major productivity booster when developing UIs.
For unit and integration testing, we are using Jest—another great open source tool by Facebook. It provides a testing framework with excellent watch mode, coverage support, fairly simple mocking and swift feedback when writing tests. As it runs in Node, you mock out all native components (though it requires some setup).
We have experimented with Appium and Amazon Device Farm for cross-platform UI automation tests. But currently, we’re focusing on a solid and fast unit testing setup that helps us catch bugs and documents the expected behavior of our code.
Everyone on the team uses their preferred editor, whether it be Visual Studio Code, Atom, or IntelliJ IDEA. To have a good and consistent development experience we ensure that all of our editors:
- Show ESlint errors
- Call eslint -- fix on file save (we never do manual formatting, we have Prettier for that)
- Understand Flow declarations, so we get autocompletion and type errors in the editor
While we are quite happy with the current setup, there is room still for improvement. One thing we want to do is to have a big set of UI tests. We’re not entirely sure yet what the best option for that would be. But in general, we now have a solid foundation on which we can build more features, and we have great checks in place that make sure our code adheres to best practices and our internal style. The development cycle is also a lot faster because of the unit tests and Storybook.
There is one more thing we feel is important when converting to React Native, and that is native modules and UI components. We will cover that in our next blog post.
Co-authored by Kevin Pelgrims.
This blog post was cross-posted from https://skovhus.github.io/converting-an-app-to-react-native/ and originally posted on Leo Innovation Labs’ medium.