What Happens When You Build Your App

Rate this content
Bookmark
Slides

How do you start your app on your simulator in the morning? Do you always run react-native run-ios? If so, you might be wasting a lot of time. Let’s check out together what a React Native app looks like under the hood. It will help us to be more efficient on a daily basis. We’ll identify the shortest steps to execute daily actions, like starting our apps as fast as possible (no more unnecessary compilations of native modules!), or dealing with pesky red errors that metro throws at us.

20 min
24 Oct, 2022

Video Summary and Transcription

Today's Talk dives deep into React Native development, exploring the development process, JavaScript-native communication, and app deployment. It highlights the app building process, the React Native Run iOS command, and development gestures for efficient execution. The Talk also emphasizes the recommended process for starting and testing your app, as well as handling the 'red screen of death' error by installing missing libraries and understanding the role of the UI manager in creating native views.

Available in Español

1. Introduction to React Native Development

Short description:

Hi everyone, I'm Charlotte, a React Native Tech Lead at BAM. Today, we'll dive deep into your application, understand what happens when you build it, and learn how to be more efficient. Let me share a story. One day, I encountered a big error and didn't know how to solve it. I used to kill everything and start from scratch, wasting time. My colleague advised me to understand what's happening inside the black box. That's what we'll do today. A quick reminder: React Native uses core components instead of HTML elements. Let's start!

Hi everyone, I'm super excited to be talking to you at React Advanced London. I'm Charlotte, I'm a React Native Tech Lead at BAM, and today we'll dive deep inside your application. We will study the inside of your app and what happens when you build it. And then we will see how we can use this information to be more efficient on a daily basis. But let me tell you a short story before.

One day I was working at my desk and one big red error appeared on my screen. The kind of error that I didn't understand and I didn't know how to solve. This day I did what I used to do every time back then to fix it. I killed everything. My app, my simulator, maybe even my metro server. And after that second step, I relaunched everything from scratch, brand new. I ran Yang install, Pod install. I rebuilt my whole app. I didn't understand what was happening inside my simulator. So I wasn't able to identify what piece of the puzzle was failing. So I started everything again. And it worked. But it was wasting a lot of time. And this day, one of my colleagues passed by and saw me killing everything without any pity. And she advised me to try to understand what was happening inside this black box. So that's what I did. And that's what we are going to do today.

One quick reminder before we start. For the ones of you who are working on the web, what you need to know about React Native is that instead of using HTML elements like divs and spans, we are going to use React Native core components, like buttons and text. And from those components, React Native is going to ask the native to create the associated Android and iOS native components. Okay. Let's start. This is a view of a React Native application in our development environment. There are two parts in this schema, a JavaScript part and a native part. On the JavaScript side, we have some code.

2. React Native Development Process

Short description:

We have JS, JSX, and TypeScript code, which will be transferred into JavaScript by Babel. Mitro, the JavaScript bundler, will bundle the JavaScript into a single file called the bundle. On the Native side, we have Swift and Objective-C on iOS, and Java and Kotlin on Android. The Native code needs to be compiled, producing an executable IPA on iOS and APK on Android. A React Native application is a native application that instantiates a JavaScript engine to compile and execute the JavaScript bundle, allowing communication between the JavaScript and native worlds.

We have JS, JSX, but also TypeScript code. This code will be transferred into JavaScript by Babel. The JSX will be transferred into JS and the JS will be transferred into an older JS without any of the new features old machines can't understand. Then we have Mitro. Mitro is a JavaScript bundler, the mobile equivalent of Webpack. It will bundle the JavaScript into a single file that's called the bundle. And React Native will only deal with this single file. If you make some changes in your JavaScript code, Mitro will aggregate those changes to the bundle and refresh your application on the fly. That's about it for the JS.

Now, let's take a look at the Native part. On the Native side, we have some Native code, either Swift and Objective-C on iOS, and Java and Kotlin on Android. If you open your app in your IDE, you will see an Android and an iOS folder. And in this iOS directory, you've got everything you need to create an iOS application. If you are building one in Swift, you would, in fact, be working within this directory.

Now, this Native code needs to be compiled, and this compilation process is going to produce an executable, an application, IPA on iOS, APK on Android. These are native applications that we will be able to install on our phone. Those two applications, the bundle and the IPA, will allow us to build our React Native application. Let's take a closer look at them. This is the inside of a React Native application. It's actually built from the IPA that was executed. A React Native application, it's really just a native application that will instantiate a JavaScript engine which will compile and execute the JavaScript bundle. The JavaScript world will be able to communicate with the native world. This goes a little bit like this. Imagine that we have this simple component rendering a button with a special title. First, the JavaScript will render his button on the screen. To do this, he will be giving instructions to the native to render the equivalent native component. So he goes, please native, could you render this button for me? And the native goes, of course. Oh, here you go. The user just pressed it. Maybe you should trigger this on press callback of yours.

3. JavaScript-Native Communication and App Deployment

Short description:

The JavaScript communicates with the native side through a bridge, which will change with the new architecture. If you want to know more, attend talks at React Advanced. Once deployed to stores, the JavaScript bundle and native application are produced at build time. Before we continue, let me ask you, do you always run React Native Runner OS to start your app in the morning?

And the JavaScript does it. In our case, it changes the button title. So the JavaScript goes, hey, native, could you change this button title for me? And the native does it. And this is how, as a user, I can now see my new button title on the screen.

Now, the communication between the JavaScript and the native is currently being handled through a bridge. The bridge is a queue where the JavaScript and the native exchange JSON messages, like please change this button title. But this will change with the new architecture that you may have heard about. We won't dive into this subject, but the main ideas of this talk will still stand within your architecture. And if you want to know more about what will change, there will be several talks about this subject at React Advanced.

So I'd advise you to listen to one of Nicola Corti's or Gunther Bord's talks. Let's get back to our React Native application. We've got our app. But maybe, one day or another, we'd like to have some users and to send it over to some stores. We said earlier that our JavaScript development environment produced the JavaScript bundle. But once we deploy to the stores, we don't have our development environment anymore. We don't need Metro to aggregate any JavaScript change with writes. In release mode, the JavaScript bundle is produced once and for all at build time. And so is the native application. We deployed that to the stores. So great. We've got our React Native application.

Before we continue, I had one quick question for you. How do you start your app in the morning? Do you by any chance happen to always run React Native Runner OS? I hope not. No, wait. Actually, I do. Otherwise, I'd have nothing to teach you. Anyway, that's what I used to do. But it wasn't the most efficient way to start my day. For the ones of you who are working on the web, React Native Runner OS is the command we use to create and run our app. It's a very practical command.

4. App Building Process

Short description:

When we build our app, it takes quite some time, about five minutes each time. Let's take a look at what happens during this process.

It launches a simulator. It builds and installs our app, and we're ready to go. The problem is that this command takes quite some time, about five minutes each time. But what's taking so long? Let's take a look at what happens when we build our app, shall we? We'll be finding here the same elements as in the first schemas, but in a more chronological view. Also, I'm talking a lot about iOS right now. But Android's pretty much the same. And for this part, keep in mind that I'm talking about the legacy architecture, not the new one, but the conclusions will remain the same. Let's get started.

5. React Native Run iOS Command

Short description:

When running React Native Run iOS, two things happen in parallel. Firstly, a metro server aggregates and transpiles the JavaScript code into a bundle. Secondly, simulators are launched, and the native code is compiled to produce an executable IPA. The native modules are loaded, and the JavaScript engine requests the bundle from Mitra. Once the bundle is received, the JavaScript engine executes it, creating native views for UI components. Your application is then live.

This is a view of our React Native Run iOS command. When we run React Native Run iOS, two things are happening in parallel. On the one hand, we are going to run a metro server. This metro server is going to aggregate all of the JavaScript code into the bundle, transpile it with Babel, and deliver this bundle. But for now, it's a server. It's branched to a port and it's waiting for instructions to come over.

On another hand, we are going to open our simulators and launch it. And we are going to take care of our native code. As we said earlier, the native code has to be compiled. And this compilation process is going to produce an application, an executable, an IPA that we are going to install on our simulator. Once it is installed, we are going to launch it.

And now two more things are happening in parallel. On the one hand, we are going to load the native modules. The native modules expose native classes to the JavaScript. Those are classes. They need to be instantiated at some point. On another hand, we are going to start the JavaScript engine which is going to make a request to Mitra to get the bundle. And at this point, if you look in your network inspector, you are going to see this request made to your own local host. You will also see on the Mitra server this progress bar. Once the JavaScript engine gets the bundle, it is going to execute it. We will traverse the JavaScript component tree giving orders to the native to create the native views every time a UI component is encountered. And that's it. Your application is live. Congratulations.

6. Development Gestures and App Startup

Short description:

Let's explore some development gestures and how to execute them efficiently in the mobile world. When making a JavaScript change, Mitra's Watchman listener system aggregates it to the bundle and triggers reloads. For native changes, the code needs to be compiled and included in the app, requiring a rebuild. Installing JavaScript dependencies can be done with YARN install, while native dependencies require running react native run iOS. Starting the app daily only requires a Mitra server, the previous device, and the installed application.

Now that we've got this, let's take a look at a few development gestures from the daily live and see how we can execute them efficiently in our mobile world. The first thing you do when you develop is well, you develop. So you make a change, a JavaScript change. This different recipe in here is the one of Mitra. Mitra has a listener system that's called Watchman that will listen to the changes you make inside the code. And when you add some JavaScript, it will aggregate it to the bundle and trigger reloads. So to see our changing our app, thanks to the hot reload, we really just need to save our code.

Now another kind of change, a trickier one that you may do in the code is a native change. This new native code you added has to be compiled and included in our app. It corresponds to this step in our tree. What we need to realize here is that this compilation process will produce a whole new app and install it on our phone. It will completely override the previous application we had installed. So to see our new native change, we have to rebuild our app, either by running React Native run iOS or by building it with Xcode.

Okay, what else do we do frequently? Oh, libraries! Say that your app is running, you are happily coding and you need to install a new JavaScript dependency. What you need to do here is just run YARN install. You see, Mitro watches our source code but it also watches our node modules. So you run YARN install and Mitro will aggregate this change to the bundle. But we don't only depend on JavaScript dependencies. We rely on some native dependencies as well. So if you added a new native dependency by running prod install, which is the command we use to add some native iOS dependency, the iOS equivalent of YARN install. If you added this new library, this new native library, this is some new native code that has to be compiled as well. So it corresponds to this step in R3. So you have to run react native run iOS to build your app again.

Now the main gesture that I wanted to check with you today is this one, how you start your app on a daily basis. Because like I said, I used to run React native run iOS every day to launch my app, but it really wasn't necessary. You see, when you run this command, you go through all of those steps, including the native code compilation, which really takes the biggest amount of time here. But unless you added a new native library during the night, you don't need to do this. Your app is already installed somewhere on a simulator in your computer. What you need to start your app is really three things. A Mitra server, the device you used the day before, and the application installed on that device.

7. Starting and Testing Your App

Short description:

The recommended process to start your app is to run a Mitra server, launch your simulator, and click on your app to launch it. Running React Native on iOS every day is not necessary, but it's still advised to run it occasionally. Testing your app on a different simulator is also important. You don't need to compile your native code again; you can install the executable on another simulator. Killing the simulator is not necessary when encountering errors. There are two main errors related to the Balances problem: one in the Javascript and one in the native world.

So the process I would recommend to start your app is this one. First, you run, you start a Mitra server by running react native start. Then you launch your simulator. You can do it in command line or using spotlight by selecting your simulator application. And then you have to click on your app on your simulator to launch it. And that's it. It saves so much time already.

One small disclaimer, though. Even though I strongly advise you not to run React Native on iOS every day to launch your app, I still advise you to run it from time to time. You see, if you're working on a project where you don't hide libraries every so often anymore, the risk is that the one day you need to build your app, it doesn't work anymore. And you don't want to spend three hours debugging this process when you have a new version to deliver to the stores.

Let's move on to the last gesture, testing your app on a different simulator. That's something that I have to do every day. I usually work on a specific simulator, but I have to test my code in different situations, with a smaller screen or without a notch, for example. Until I learned about all of this, I used to run React Native Run iOS every day to do it. But it isn't necessary. You may start to see why now. You don't need to compile your native code again. Your native code is not specific to a particular iPhone. All you need to do is to take the executable you already built and install it on another simulator. On Android, you can do this by running ADP install. On iOS, you can do this in Xcode by selecting Run Without Building.

You may have noticed that none of those steps include killing me through your simulator. That's something that I used to do every time I encountered one of those big red errors that I didn't know how to get rid of. But now that we know what's inside this black box, maybe we can try together to understand those errors and see how we can fixed them without killing anything. We basically encounter two main errors related to the Balances problem. The first one happens in the Javascript, while the other one happens in the native world. Let's take a look at the first one. It tells us that our library could not be found within the project. So, it means that we are using a library that we haven't installed.

8. Handling Red Screen of Death Error

Short description:

To fix the 'red screen of death' error, you need to install the missing library by running 'yarn install'. If the library has a native part, you also need to install it using 'pod install' and rebuild the app with 'react native run iOS'. Understanding the UI manager's role in creating native views is crucial. If the UI manager can't find the native element, it means the library's native part was not installed properly. Make sure to install both the JavaScript and native parts to avoid errors. Thank you for listening!

So, we just need to install it by running yarm install and here we go again. This error can also happen in another situation. Imagine that while your app is running, you pull your main branch and someone else added a library. Before you get the chance to run yarm install, you're using a library that you haven't installed yet. So, JavaScript's saying I don't know this thing you're trying to use. So, you just run yarm install.

But what's instant? Think about this. This library may also have a native part. In this case, you have to install it as well by running part install and to compile it. So, you have to rebuild your app by running reg native run iOS.

Let's move on to the second error. It tells us that it can't find our library element in the UI manager. The UI manager handles UI operations, like creating native views. When the JavaScript asks for a native element to be created, the UI manager handles that request and transfers it to the native part. And in this error, the UI manager is saying that it doesn't know the native element. So it means our library has not been installed properly. And it's specifically the native part that's missing. We're sure that the JavaScript part was installed. Otherwise, we would have had an error sooner in the JavaScript side. The error we looked at just before actually. In our case, this error happens afterwards when the JavaScript asks the native to render the components. To fix this, we just need to install the native part by running part install and then React Native run IOS.

So I hope that the next time you encounter the red screen of death, you'll understand what's going on behind the hood. And you'll know how to handle it. That's it for me. Thank you so much for listening. It was my first talk and I was really glad to give it. Also, please don't kill your simulator.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Advanced Conference 2022React Advanced Conference 2022
25 min
A Guide to React Rendering Behavior
Top Content
React is a library for "rendering" UI from components, but many users find themselves confused about how React rendering actually works. What do terms like "rendering", "reconciliation", "Fibers", and "committing" actually mean? When do renders happen? How does Context affect rendering, and how do libraries like Redux cause updates? In this talk, we'll clear up the confusion and provide a solid foundation for understanding when, why, and how React renders. We'll look at: - What "rendering" actually is - How React queues renders and the standard rendering behavior - How keys and component types are used in rendering - Techniques for optimizing render performance - How context usage affects rendering behavior| - How external libraries tie into React rendering
React Summit 2023React Summit 2023
23 min
React Concurrency, Explained
Top Content
React 18! Concurrent features! You might’ve already tried the new APIs like useTransition, or you might’ve just heard of them. But do you know how React 18 achieves the performance wins it brings with itself? In this talk, let’s peek under the hood of React 18’s performance features: - How React 18 lowers the time your page stays frozen (aka TBT) - What exactly happens in the main thread when you run useTransition() - What’s the catch with the improvements (there’s no free cake!), and why Vue.js and Preact straight refused to ship anything similar
React Summit 2022React Summit 2022
27 min
Inside Fiber: the in-depth overview you wanted a TLDR for
I want to provide an in-depth overview of the important concepts behind reconciliation. We'll then explore how React uses the algorithm and go through a few magic words we hear a lot, like coroutines, continuations, fibers, generators, algebraic effects and see how they all relate to React.js.
TypeScript Congress 2023TypeScript Congress 2023
31 min
Making Magic: Building a TypeScript-First Framework
I'll dive into the internals of Nuxt to describe how we've built a TypeScript-first framework that is deeply integrated with the user's IDE and type checking setup to offer end-to-end full-stack type safety, hints for layouts, middleware and more, typed runtime configuration options and even typed routing. Plus, I'll highlight what I'm most excited about doing in the days to come and how TypeScript makes that possible not just for us but for any library author.
React Advanced Conference 2022React Advanced Conference 2022
29 min
Deep Diving on Concurrent React
Writing fluid user interfaces becomes more and more challenging as the application complexity increases. In this talk, we’ll explore how proper scheduling improves your app’s experience by diving into some of the concurrent React features, understanding their rationales, and how they work under the hood.
React Advanced Conference 2023React Advanced Conference 2023
29 min
Raising the Bar: Our Journey Making React Native a Preferred Choice
At Microsoft, we're committed to providing our teams with the best tools and technologies to build high-quality mobile applications. React Native has long been a preferred choice for its high performance and great user experience, but getting stakeholders on board can be a challenge. In this talk, we will share our journey of making React Native a preferred choice for stakeholders who prioritize ease of integration and developer experience. We'll discuss the specific strategies we used to achieve our goal and the results we achieved.

Workshops on related topic

React Summit 2023React Summit 2023
170 min
React Performance Debugging Masterclass
Top Content
Featured WorkshopFree
Ivan’s first attempts at performance debugging were chaotic. He would see a slow interaction, try a random optimization, see that it didn't help, and keep trying other optimizations until he found the right one (or gave up).
Back then, Ivan didn’t know how to use performance devtools well. He would do a recording in Chrome DevTools or React Profiler, poke around it, try clicking random things, and then close it in frustration a few minutes later. Now, Ivan knows exactly where and what to look for. And in this workshop, Ivan will teach you that too.
Here’s how this is going to work. We’ll take a slow app → debug it (using tools like Chrome DevTools, React Profiler, and why-did-you-render) → pinpoint the bottleneck → and then repeat, several times more. We won’t talk about the solutions (in 90% of the cases, it’s just the ol’ regular useMemo() or memo()). But we’ll talk about everything that comes before – and learn how to analyze any React performance problem, step by step.
(Note: This workshop is best suited for engineers who are already familiar with how useMemo() and memo() work – but want to get better at using the performance tools around React. Also, we’ll be covering interaction performance, not load speed, so you won’t hear a word about Lighthouse 🤐)
React Summit Remote Edition 2021React Summit Remote Edition 2021
177 min
React Hooks Tips Only the Pros Know
Top Content
Featured Workshop
The addition of the hooks API to React was quite a major change. Before hooks most components had to be class based. Now, with hooks, these are often much simpler functional components. Hooks can be really simple to use. Almost deceptively simple. Because there are still plenty of ways you can mess up with hooks. And it often turns out there are many ways where you can improve your components a better understanding of how each React hook can be used.You will learn all about the pros and cons of the various hooks. You will learn when to use useState() versus useReducer(). We will look at using useContext() efficiently. You will see when to use useLayoutEffect() and when useEffect() is better.
React Summit 2023React Summit 2023
151 min
Designing Effective Tests With React Testing Library
Top Content
Featured Workshop
React Testing Library is a great framework for React component tests because there are a lot of questions it answers for you, so you don’t need to worry about those questions. But that doesn’t mean testing is easy. There are still a lot of questions you have to figure out for yourself: How many component tests should you write vs end-to-end tests or lower-level unit tests? How can you test a certain line of code that is tricky to test? And what in the world are you supposed to do about that persistent act() warning?
In this three-hour workshop we’ll introduce React Testing Library along with a mental model for how to think about designing your component tests. This mental model will help you see how to test each bit of logic, whether or not to mock dependencies, and will help improve the design of your components. You’ll walk away with the tools, techniques, and principles you need to implement low-cost, high-value component tests.
Table of contents- The different kinds of React application tests, and where component tests fit in- A mental model for thinking about the inputs and outputs of the components you test- Options for selecting DOM elements to verify and interact with them- The value of mocks and why they shouldn’t be avoided- The challenges with asynchrony in RTL tests and how to handle them
Prerequisites- Familiarity with building applications with React- Basic experience writing automated tests with Jest or another unit testing framework- You do not need any experience with React Testing Library- Machine setup: Node LTS, Yarn
React Advanced Conference 2022React Advanced Conference 2022
81 min
Introducing FlashList: Let's build a performant React Native list all together
Top Content
WorkshopFree
In this workshop you’ll learn why we created FlashList at Shopify and how you can use it in your code today. We will show you how to take a list that is not performant in FlatList and make it performant using FlashList with minimum effort. We will use tools like Flipper, our own benchmarking code, and teach you how the FlashList API can cover more complex use cases and still keep a top-notch performance.You will know:- Quick presentation about what FlashList, why we built, etc.- Migrating from FlatList to FlashList- Teaching how to write a performant list- Utilizing the tools provided by FlashList library (mainly the useBenchmark hook)- Using the Flipper plugins (flame graph, our lists profiler, UI & JS FPS profiler, etc.)- Optimizing performance of FlashList by using more advanced props like `getType`- 5-6 sample tasks where we’ll uncover and fix issues together- Q&A with Shopify team
React Summit 2022React Summit 2022
117 min
Detox 101: How to write stable end-to-end tests for your React Native application
Top Content
WorkshopFree
Compared to unit testing, end-to-end testing aims to interact with your application just like a real user. And as we all know it can be pretty challenging. Especially when we talk about Mobile applications.
Tests rely on many conditions and are considered to be slow and flaky. On the other hand - end-to-end tests can give the greatest confidence that your app is working. And if done right - can become an amazing tool for boosting developer velocity.
Detox is a gray-box end-to-end testing framework for mobile apps. Developed by Wix to solve the problem of slowness and flakiness and used by React Native itself as its E2E testing tool.
Join me on this workshop to learn how to make your mobile end-to-end tests with Detox rock.
Prerequisites- iOS/Android: MacOS Catalina or newer- Android only: Linux- Install before the workshop
React Summit Remote Edition 2021React Summit Remote Edition 2021
60 min
How to Build an Interactive “Wheel of Fortune” Animation with React Native
Top Content
Workshop
- Intro - Cleo & our mission- What we want to build, how it fits into our product & purpose, run through designs- Getting started with environment set up & “hello world”- Intro to React Native Animation- Step 1: Spinning the wheel on a button press- Step 2: Dragging the wheel to give it velocity- Step 3: Adding friction to the wheel to slow it down- Step 4 (stretch): Adding haptics for an immersive feel