My Experience Moving from React to React Native
A Quick Synopsis of the Good, the Bad, and the Buggy
After developing projects in React for some time now (and loving it), I thought it would be an exciting opportunity to venture into the realm of React Native. I’ve heard quite a bit about React Native, both the good and the not-so-good, and thought I would share my experience here.
Like React, React Native uses a component-based structure that is focused on modularity and separation of concerns. And like React, React Native utilizes JSX as the script language in its components. Hooks are also available (yay hooks!) for sophisticated functionality and state-management. Unlike React though, React Native does not use JSX to render HTML for the UI. You are rendering to a phone OS, not a browser, so React Native provides the dev with primitives that allow for rendering and renders, well, JSX. It’s not that bad, once you get a hang of it, but at first it may feel slightly restrictive to the normal React dev. Additionally, some typical callback props customary in React (onChange, onSubmit, etc.) are slightly different in React Native (onPress, onChangeText, etc.). For whatever reason those changes exist, your guess is as good as mine. There are a litany of other subtle differences, one of which that stands-out is navigation between screens vs. routing through components. Obviously, navigation architecture on mobile devices was built with the screen interface in mind and what limited space the user has to see and do things. The React Navigation library can help you, well, navigate, and this is different from using a router to get around.
When running and testing apps, devs can utilize Expo instead of using the browser directly like with React. Expo is essentially a platform that contains a set of tools and services built around React Native and native platforms that help you develop, build, deploy, and quickly iterate on iOS, Android, and web apps from the same JavaScript/TypeScript codebase. You can run a iOS or Android simulator on your computer to mimic the interface of your app or, if you download the expo app, you can test your app on your own personal device. I personally like to start with a simulator on my computer and then move to the phone once my app functionality is ironed out.
The most obvious standout advantage of using React Native vs. native languages is that React Native is OS agnostic. If you are a startup with limited resources or you are in a hurry to get an app live, React Native saves you time and money. Time because you are otherwise developing with two different codebases and money because you don’t need two different devs or teams to develop the app and manage it overtime. With that said, there have been a number of companies that have introduced React Native in their stack and may use it for 50% of their functionality, relying on native languages for the other 50%. According to some devs, this does not always go smoothly. And accounts that React Native’s load times are slower is not uncommon. It is also not an uncommon complaint that libraries and packages to support React Native functionality are too often deprecated, inconsistent, or lacking in support. This is partly why some established mobile dev teams are hesitant to introduce React Native.
My biggest, and I cannot overstate this enough, inconvenience with React Native is debugging and styling choices. The limitations with styling, I assume really stem from mobile architecture (I could be completely wrong about this, btw). When working with React, for better or worse, you have lots of options with styling: importing a traditional stylesheet, using inline styling, taking advantage of purely styled components. React Native doesn’t grant you that luxury. In many cases, you’ll use a StyleSheet primitive that allows you to incorporate inline styling. And honestly, its not a bad way to go assuming that your mobile app is far less expansive that your React app. You can easily style components and reuse them too. But in terms of the styling libraries, they exist, but aren’t nearly as prolific as the ones for React. When it comes to debugging, I find many of the error messages to be cryptic and lacking intuition. Maybe because I’ve been spoiled with Ruby and React debugging for so long, but I find React Native debugging to be less than optimal. You can use react dev tools like you would on your browser, albeit in a different format. It is relatively the same experience as it is with React, but it feels a little clunkier. Honestly, it feels like something that was intended for a browser and shoehorned into a mobile testing environment.
You can use Redux in React Native (I don’t know how you could have a sophisticated app without it) and in doing so can use Redux dev tools as well to monitor your store. Again, setup and implementation is a tad bit clunkier than using React, in my opinion. Recently, I’ve started using the context API to store global state instead of Redux on a few of my projects. Why, you might ask? Good question. Honestly, for the exposure, but one major limiting factor I’ve found using context on React Native is that debugging and monitoring state can be a nightmare. It feels like walking through a maze blindfolded. There are dev tools designed for context that are similar to Redux dev tools, but that are intended for React testing. I can’t find anything available for context that has a similar format. Yes, the react dev tools do give you access to context in your components, but its just not the same as redux dev tools (yes, this sentence is meant to be read with whiny intonation).
And honestly, if you can’t debug easily with complex architecture, then whats the point? Generally speaking, a common point that supports and discourages implementation of React Native arises: its quick and easy to get a “universal” app up and running. If you are running a sophisticated app with complicated architecture, you might run into to some cumbersome roadblocks throughout the process.
If you are a React developer, it’s pretty safe to say that you are spoiled with supported libraries and packages. If your app is in need of some enhanced functionality, whether it’s rendering a pdf or having enhanced styled components, there is probably a package (or several) for that. The same can’t necessarily be said for React Native. When you work in React Native, you need to be comfortable with limitations if you are coming from a React background.
I like to think that React Native was built for people like me — devs who work in React, enjoy it, and are curious to try their hands at mobile development. When taking a cursory glance at a React Native component, you may have a hard time distinguishing between it and a React component (that’s by design, but it’s still obviously there). One thing that supports the evolution of React Native, and why I think it is worthwhile to learn, is its backing from the React dev team and Facebook, by proxy. React has exploded in popularity in the last decade and is, in many ways, the preferred Javascript front-end framework (sorry, Angular). I have to believe that companies with such massive reach, like facebook, are committed to React Native’s success (crossing fingers). OS agnosticism is a real gift when using React Native and I hope for other junior devs it continues to be a preferred choice, purely for selfish reasons. With popularity comes support, investment, and reliability and why wouldn’t you want a development framework that is solid, cross-platform, easy to understand, and potentially more time and cost effective?