Let’s dive in.
Okay so in order to understand React, it helps to understand the history of why React was built. Programming user interfaces for the web browser has sucked, since forever, and over the decades different teams have tried different approaches to make it suck less. This sounds kind of crappy, and for a while it really was, but then something really curious happened: the pressure to find a better way to build web software kept building and building until it outweighed the difficulty of the constraints of web browsers. The overwhelming amount of pressure to mitigate the awfulness of web programming led to a lot of really innovative ideas. One of the most famous ones is jQuery.
“Really slow” is a relative term, so let’s unpack what that means. Certain changes to the DOM can trigger what’s called a reflow – basically, the layout of the website gets re-calculated by the browser. A reflow is a synchronous event that can be easily triggered inadvertently by programmers, and it’s easy for web apps to have performance problems based on this bottleneck (you can read more about layout thrashing here). Browser makers go to great lengths to optimize their reflow algorithms, but the easiest win for web app performance is being smart about when to trigger a reflow.
A kind of arms race between frameworks for web performance has been going for years, and it’s been really exciting! And that brings us to React. React solves the slow DOM API problem by abstracting away the state of the application. There are lots of implementation details (like, people usually mention the Virtual DOM when explaining React) but the most important thing is that React is declarative.
So what the heck is that? Well it takes a second to explain.
User interfaces are built in React by building and composing reusable components, which are little pieces of code that turn input properties (called props) into a user interface. A React app is really just a big tree of components; each parent passes its child components the props that the child needs to render itself, and so on. This is declarative because if a component is passed the same props, it will produce the same user interface every time.
(Components can maintain their own internal state independent of React, but it’s totally private to that component and can only be modified through a centralized, asynchronous API.)
I’ve always liked (and advocated for) iOS functional reactive frameworks like RxSwift, ReactiveSwift, Interstellar, etc on iOS. However, I’ve never felt entirely satisfied by them. They are an excellent way to handle state, but they themselves operate within and are built atop a stateful abstraction layer (UIKit). Subsequently, the complexity of these frameworks is fundamentally constrained on the lower bounds in a way that React isn’t.
There’s just too much incidental complexity to how these frameworks need to integrate with the rest of the app. Contrast that complexity with React, where there are no observables or flat maps or signal transforms; you just write components in declarative way and you get all the benefits of reactive UIs for free.
Yeah, for free.
It’s like a functional reactive programmer’s dream. Unidirectional data flow, asynchronous everything, everything, it’s so good. The declarative abstraction that React provides is elegant and thoughtful, and the React developers have continuously improved the API and tooling for React over the past five years.
If you’re keen to learn more, you should check out the React tutorial; it includes a great, in-depth explanation of why immutability and declarative APIs are so important. You can also read more about why React is so popular here.
My point is: React is unbelievably good. But it’s not the only reason to use React Native.
iOS developers are a smaller community than web developers, who tend to specialize more. The web has also been around longer, too, and it’s lacked any authority to direct its development. How cool is that! A whole other community of developers, evolving under totally different constraints.
And if you build your iOS app in React Native, you get access to that ecosystem. That means Relay/Apollo, styled components, Jest, Enzyme, prettier, Husky, many other great tools, and a long tail of less well-known but nonetheless very useful tools. I cannot do justice to this feeling, you just need to experience it to understand.
So yes, you’ll have a lot of dependencies. But you’ll also learn to see building software from a new perspective. That learning experience alone, to me, is a worth a few hundred node modules.
The thing is: this is all just what I think. Different people with different backgrounds and different priorities are going to come to different conclusions. I think that’s totally okay. There are lots of reasons not to use React Native; when my colleague Eloy describes why Artsy adopted it, he literally begins with a bunch of React Native downsides. We’re not hiding anything!
A lot of iOS apps (many? most?) can be entirely described as “software that turns API calls into user interfaces, and user interactions into API calls.” That’s a problem that React is tailored to solve, and React Native adopts that solution to iOS and Android really really well.
React Native isn’t perfect, and it’s not suitable for every app. But nothing is! UIKit isn’t perfect for every app, either. There simply are no silver bullets in programming. React solves the problem of programming UIs to such a degree of success that, when combined with a fantastic language and a vibrant ecosystem, it makes a compelling case for use in a lot of apps.