apps with React. We are at a React conference and there were other talks about React Native, therefore I’ll assume you’re already familiar with React and basics of React Native.
React Native compared to traditional mobile development. If you’re developing for the web, one thing you’re used to is that you can reload to quickly see your changes. You probably know that React Native gives you that same experience. Compare that to compiling and copying the binary to the device every time you make a change.
server (a custom packager, you can imagine it as something similar to Webpack) that runs on your machine and serves a bundle containing all the JS needed to run your app. On a small change it can return a new bundle really fast. GET /index.bundle
I don’t have to learn a completely different set APIs for Android and iOS. For example, I don’t need to learn twice how to write to disk, make network requests, or show a scrollable list of items.
row: { flexDirection: 'row', alignItems: 'center', padding: 5, backgroundColor: 'white', }, }; That’s also true for layout, which is done exactly the same way on Android and iOS using Flexbox that you already know from the web.
is we remove all the native views that only define layout but are not visible in any way (e.g. don’t have color). This means Android has to do less work traversing the view hierarchy which means a more performant UI.
have native look and feel, I encourage you to try them out. You’ll need to have ads on Facebook to have the full experience but you can play with it even without having ads.
shared What was the experience for the Ads Manager team like? It only took them 3 months to build the Android app once the iOS version was finished. It was one team of people building for both platforms. Most people on the team had mainly JS experience, some iOS and some Android experience. It turned out they could even share most of the code between platforms. Note that code sharing wasn’t an explicit goal - React Native is learn once write anywhere, not write once run anywhere.
check what platform you’re running on. On this slide notice another interesting thing - AdsManagerText - a component that defines a consistent look for text across the whole app, making it easy to change it in one place.
screen on iOS and Android. There’s a ScrollView that has the same contents on both platforms but you can see that it has different pull-to-refresh behavior, specific to the platform.
deeper and look how React Native runs your code. It’s important to note I’ll focus on Android here but the iOS architecture is very similar. You can read about the iOS architecture in a blogpost by my colleague Tadeu.
React Native is a bridge that lets native code calls JS and vice versa. There’s a JS VM (we use JavaScriptCore) running your code. On Android, JavaScriptCore needs to ship with your application which means a Hello World Android app is about 3.5MB. On iOS JavaScriptCore is part of the system.
get about the architecture of React Native is whether the application code runs in a WebView. There is no WebView, it’s JS running in a VM and controlling native UI.
{}); [1, 1, [‘MyApp’, {}]] It’s important to realize that we always start in native. In this case native decided to start your app. It sends a function id and arguments to JS using our custom JSON-based protocol over the C++ bridge.
{…}); … UIManagerModule#createView(2, ‘View’, …) View newView = new View(); UIManagerModule#createView(3, ‘Text’, …) TextView newView = new TextView(); … [[2, 3, [2, ‘View’, {…}]], [2, 3, [3, ‘Text’, {…}]]] JS calls that function which in turn leads to a bunch of calls from JS to native. For example, create a TextView, send a network request. These are all batched together and sent back to native asynchronously.
{…}); … [[2, 3, [2, ‘View’, {…}]], [2, 3, [3, ‘Text’, {…}]]] The calls are batched together so we don’t pay the overhead for each individual call. However, in some cases, such as when JS is doing lots of work, it might be better to split the batch into several batches. Imagine JS wants to create a few views, then read something from disk and do lots of computation, then update more views. It can be better to flush the queue of calls (see MessageQueue.js) into native early - this way the person using your app can see something on the screen meanwhile JS is still doing work.
In the previous slide we said the calls between native and JS are asynchronous. To explain that let’s look at the threading model. There’s the main thread with a queue of events. This is the Android main thread. Then there are two additional threads - one that runs operations on native modules and one that runs your JS (on iOS this works a little bit differently, refer to Tadeu’s blogpost). Each thread is processing a separate queue of events.
Touch Event Now imagine the OS told us (on the native main thread) there’s a touch event. The touch event here serves just as an example. If you are interested in how touch handling works refer to the awesome talk by @alex_frantic in the Videos section on the React Native website.
Event UI Event Queue Native Modules Event Queue JS Event Queue Based on the touch event we add an event to the JS queue. The JS thread synchronously calls your application code via the bridge. This runs your JS which calls e.g. setState and render.
bridge -> Runs JS Touch Event Touch Event UI Event Queue Native Modules Event Queue JS Event Queue Dispatch View Updates Update UI Dispatch View Updates Update UI As you saw in the bridge overview, your code returns operations to be done by native modules. These can be things like adding, removing or updating native views, sending network requests etc. Then on the native modules thread we calculate new layout and finally update the views that need to change, on the main thread. Why not do layout in JS? We need to measure text - only native can do that. The whole cycle from the touch event to updating the UI should ideally happen within 16ms: this is how JS- driven animations work too but instead of a touch event there’s a timer event that fires on every frame.
this can cause dropped frames. A workaround for this is to use the InteractionManager to delay work until animations have finished. In the future we might look into offloading animations created using the Animated API to run entirely in native.
some state and methods that JS can call. In this example, we’re calling a Dialog module in JS which translates to a call on the native dialog module in Java.
TextView(getContext()) => new Switch(getContext()) View managers define how JS views map to native views. When you specify you want to render a Switch in JS there’s a View Manager that knows how to do that and creates an Android Switch.
TextView(getContext()) => new Switch(getContext()) The coolest thing about this is that you can easily define your own view managers and modules. This is my other favorite part about React Native - you can simply drop down to native code when needed. … define your own
start using the new native feature in your app, create a simple package with you view manager. Then simply add that package to your app’s MainActivity.
your package to npm and register it on react.parts to make it easily discoverable. Then everyone can find and use your code in their apps. The process of creating and linking native modules could be made smoother, we plan to work on that.
of stability master publish to npm e.g. 0.14.0-rc Every two weeks we cut a release branch from master and publish to npm so you can try out the new release candidate.
branch: e.g 0.14 2 weeks of stability 2 weeks of development master publish to npm e.g. 0.14.0-rc We cherry-pick bug-fixes and sometimes small features from master during the following two weeks, then publish to npm and the whole process repeats.
store the code internally. The source of truth for the React Native codebase is an internal Mercurial repo called fbsource. Here’s a simplified illustration of its layout. The react- native-github folder is a copy of what you see on github. We also have some Facebook-specific extensions like error reporting to the Facebook backend and of course there are apps like the Ads Manager, for example.
tool called Phabricator. Each code change is submitted to Phabricator and is called a “diff”. It is very similar to a pull request on github. A diff has to be reviewed by at least one person. Phabricator is integrated with our CI system - what you see at the bottom are test results. A lot of these tests are commit-blocking.
we create a patch only for those files that are open source (in the react-native- github folder), apply this to the github repo and push. This is done by a job that runs every minute.
The most important thing in this slide are the Ads Manager tests. A pull request can affect closed- source apps and we need to make sure everything works when we merge the code into the fb repo.
One reason is a lot of those issues are really questions. It would be awesome to have a way to put a banner on github saying those questions are best asked on Stack Overflow.
voting system. We’d really like to know what the most important things are for you guys. We started using a website called Product Pains. You help us by voting, submitting new issues there and above all helping fix the most important ones.
Android to feature parity with iOS. This means open sourcing more of the views and modules we’ve been using internally. To do that we need to clean up the APIs and add good examples. I’m working on this.
Here’s an old version of documentation for one of the most common things people try to do - using an Android device for development. After a few conversations on github and Twitter I realized:
get stuck. It’s important to note this particular part of the docs has been improved only thanks to the feedback on Twitter. We’ve written the Android docs but we are Android engineers so it’s often not obvious what’s difficult. You guys are in the best position to tell us what needs to be clarified. Tweet at @martinkonicek or even better send pull requests that improve documentation every time you get even a little bit stuck. Happy to review them.