Skip to main content

23 posts tagged with "engineering"

View All Tags

Β· 3 min read
Mike Grabowski

The React Native monthly meeting continues! Here are the notes from each team:

Callstack​

  • React Native EU is over. More than 300 participants from 33 countries have visited Wroclaw. Talks can be found on YouTube.
  • We are slowly getting back to our open source schedule after the conference. One thing worth mentioning is that we are working on a next release of react-native-opentok that fixes most of the existing issues.

GeekyAnts​

Trying to lower the entry barrier for the developers embracing React Native with the following things:

  • Announced BuilderX.io at React Native EU. BuilderX is a design tool that directly works with JavaScript files (only React Native is supported at the moment) to generate beautiful, readable, and editable code.
  • Launched ReactNativeSeed.com which provides a set of boilerplates for your next React Native project. It comes with a variety of options that include TypeScript & Flow for data-types, MobX, Redux, and mobx-state-tree for state-management with CRNA and plain React-Native as the stack.

Expo​

  • Will release SDK 21 shortly, which adds support for react-native 0.48.3 and a bunch of bugfixes/reliability improvements/new features in the Expo SDK, including video recording, a new splash screen API, support for react-native-gesture-handler, and improved error handling.
  • Re: react-native-gesture-handler, Krzysztof Magiera of Software Mansion continues pushing this forward and we've been helping him with testing it and funding part of his development time. Having this integrated in Expo in SDK21 will allow people to play with it easily in Snack, so we're excited to see what people come up with.
  • Re: improved error logging / handling - see this gist of an internal Expo PR for details on logging, (in particular, "Problem 2"), and this commit for a change that handles failed attempts to import npm standard library modules. There is plenty of opportunity to improve error messages upstream in React Native in this way and we will work on follow up upstream PRs. It would be great for the community to get involved too.
  • native.directory continues to grow, you can add your projects from the GitHub repo.
  • Visit hackathons around North America, including PennApps, Hack The North, HackMIT, and soon MHacks.

Facebook​

  • Working on improving <Text> and <TextInput> components on Android. (Native auto-growing for <TextInput>; deeply nested <Text> components layout issues; better code structure; performance optimizations).
  • We're still looking for additional contributors who would like to help triage issues and pull requests.

Microsoft​

  • Released Code Signing feature for CodePush. React Native developers are now able to sign their application bundles in CodePush. The announcement can be found here
  • Working on completing integration of CodePush to Mobile Center. Considering test/crash integration as well.

Next session​

The next session is scheduled for Wednesday 10, October 2017. As this was only our fourth meeting, we'd like to know how do these notes benefit the React Native community. Feel free to ping me on Twitter if you have any suggestion on how we should improve the output of the meeting.

Β· 5 min read
Mike Grabowski

The React Native monthly meeting continues! This month's meeting was a bit shorter as most of our teams were busy shipping. Next month, we are at React Native EU conference in Wroclaw, Poland. Make sure to grab a ticket and see you there in person! Meanwhile, let's see what our teams are up to.

Teams​

On this third meeting, we had 5 teams join us:

Notes​

Here are the notes from each team:

Callstack​

  • Recently open sourced react-native-material-palette. It extracts prominent colors from images to help you create visually engaging apps. It's Android only at the moment, but we are looking into adding support for iOS in the future.
  • We have landed HMR support into haul and a bunch of other, cool stuff! Check out latest releases.
  • React Native EU 2017 is coming! Next month is all about React Native and Poland! Make sure to grab last tickets available here.

Expo​

  • Released support for installing npm packages on Snack. Usual Expo restrictions apply -- packages can't depend on custom native APIs that aren't already included in Expo. We are also working on supporting multiple files and uploading assets in Snack. Satyajit will talk about Snack at React Native Europe.
  • Released SDK20 with camera, payments, secure storage, magnetometer, pause/resume fs downloads, and improved splash/loading screen.
  • Continuing to work with Krzysztof on react-native-gesture-handler. Please give it a try, rebuild some gesture that you have previously built using PanResponder or native gesture recognizers and let us know what issues you encounter.
  • Experimenting with JSC debugging protocol, working on a bunch of feature requests on Canny.

Facebook​

  • Last month we discussed management of the GitHub issue tracker and that we would try to make improvements to address the maintainability of the project.
  • Currently, the number of open issues is holding steady at around 600, and it seems like it may stay that way for a while. In the past month, we have closed 690 issues due to lack of activity (defined as no comments in the last 60 days). Out of those 690 issues, 58 were re-opened for a variety of reasons (a maintainer committed to providing a fix, or a contributor made a great case for keeping the issue open).
  • We plan to continue with the automated closing of stale issues for the foreseeable future. We’d like to be in a state where every impactful issue opened in the tracker is acted upon, but we’re not there yet. We need all the help we can from maintainers to triage issues and make sure we don't miss issues that introduce regressions or introduce breaking changes, especially those that affect newly created projects. People interested in helping out can use the Facebook GitHub Bot to triage issues and pull requests. The new Maintainers Guide contains more information on triage and use of the GitHub Bot. Please add yourself to the issue task force and encourage other active community members to do the same!

Microsoft​

  • The new Skype app is built on top of React Native in order to facilitate sharing as much code between platforms as possible. The React Native-based Skype app is currently available in the Android and iOS app stores.
  • While building the Skype app on React Native, we send pull requests to React Native in order to address bugs and missing features that we come across. So far, we've gotten about 70 pull requests merged.
  • React Native enabled us to power both the Android and iOS Skype apps from the same codebase. We also want to use that codebase to power the Skype web app. To help us achieve that goal, we built and open sourced a thin layer on top of React/React Native called ReactXP. ReactXP provides a set of cross platform components that get mapped to React Native when targeting iOS/Android and to react-dom when targeting the web. ReactXP's goals are similar to another open source library called React Native for Web. There's a brief description of how the approaches of these libraries differ in the ReactXP FAQ.

Shoutem​

  • We are continuing our efforts on improving and simplifying the developer experience when building apps using Shoutem.
  • Started migrating all our apps to react-navigation, but we ended postponing this until a more stable version is released, or one of the native navigation solutions becomes stable.
  • Updating all our extensions and most of our open source libraries (animation, theme, ui) to React Native 0.47.1.

Next session​

The next session is scheduled for Wednesday 13, September 2017. As this was only our third meeting, we'd like to know how do these notes benefit the React Native community. Feel free to ping me on Twitter if you have any suggestion on how we should improve the output of the meeting.

Β· 5 min read

React Native is used in multiple places across multiple apps in the Facebook family including a top level tab in the main Facebook apps. Our focus for this post is a highly visible product, Marketplace. It is available in a dozen or so countries and enables users to discover products and services provided by other users.

In the first half of 2017, through the joint effort of the Relay Team, the Marketplace team, the Mobile JS Platform team, and the React Native team, we cut Marketplace Time to Interaction (TTI) in half for Android Year Class 2010-11 devices. Facebook has historically considered these devices as low-end Android devices, and they have the slowest TTIs on any platform or device type.

A typical React Native startup looks something like this:

Disclaimer: ratios aren't representative and will vary depending on how React Native is configured and used.

We first initialize the React Native core (aka the β€œBridge”) before running the product specific JavaScript which determines what native views React Native will render in the Native Processing Time.

A different approach​

One of the earlier mistakes that we made was to let Systrace and CTScan drive our performance efforts. These tools helped us find a lot of low-hanging fruit in 2016, but we discovered that both Systrace and CTScan are not representative of production scenarios and cannot emulate what happens in the wild. Ratios of time spent in the breakdowns are often incorrect and, wildly off-base at times. At the extreme, some things that we expected to take a few milliseconds actually take hundreds or thousands of milliseconds. That said, CTScan is useful and we've found it catches a third of regressions before they hit production.

On Android, we attribute the shortcomings of these tools to the fact that 1) React Native is a multithreaded framework, 2) Marketplace is co-located with a multitude of complex views such as Newsfeed and other top-level tabs, and 3) computation times vary wildly. Thus, this half, we let production measurements and breakdowns drive almost all of our decision making and prioritization.

Down the path of production instrumentation​

Instrumenting production may sound simple on the surface, but it turned out to be quite a complex process. It took multiple iteration cycles of 2-3 weeks each; due to the latency of landing a commit in master, to pushing the app to the Play Store, to gathering sufficient production samples to have confidence in our work. Each iteration cycle involved discovering if our breakdowns were accurate, if they had the right level of granularity, and if they properly added up to the whole time span. We could not rely on alpha and beta releases because they are not representative of the general population. In essence, we very tediously built a very accurate production trace based on the aggregate of millions of samples.

One of the reasons we meticulously verified that every millisecond in breakdowns properly added up to their parent metrics was that we realized early on there were gaps in our instrumentation. It turned out that our initial breakdowns did not account for stalls caused by thread jumps. Thread jumps themselves aren't expensive, but thread jumps to busy threads already doing work are very expensive. We eventually reproduced these blockages locally by sprinkling Thread.sleep() calls at the right moments, and we managed to fix them by:

  1. removing our dependency on AsyncTask,
  2. undoing the forced initialization of ReactContext and NativeModules on the UI thread, and
  3. removing the dependency on measuring the ReactRootView at initialization time.

Together, removing these thread blockage issues reduced the startup time by over 25%.

Production metrics also challenged some of our prior assumptions. For example, we used to pre-load many JavaScript modules on the startup path under the assumption that co-locating modules in one bundle would reduce their initialization cost. However, the cost of pre-loading and co-locating these modules far outweighed the benefits. By re-configuring our inline require blacklists and removing JavaScript modules from the startup path, we were able to avoid loading unnecessary modules such as Relay Classic (when only Relay Modern was necessary). Today, our RUN_JS_BUNDLE breakdown is over 75% faster.

We also found wins by investigating product-specific native modules. For example, by lazily injecting a native module's dependencies, we reduced that native module's cost by 98%. By removing the contention of Marketplace startup with other products, we reduced startup by an equivalent interval.

The best part is that many of these improvements are broadly applicable to all screens built with React Native.

Conclusion​

People assume that React Native startup performance problems are caused by JavaScript being slow or exceedingly high network times. While speeding up things like JavaScript would bring down TTI by a non-trivial sum, each of these contribute a much smaller percentage of TTI than was previously believed.

The lesson so far has been to measure, measure, measure! Some wins come from moving run-time costs to build time, such as Relay Modern and Lazy NativeModules. Other wins come from avoiding work by being smarter about parallelizing code or removing dead code. And some wins come from large architectural changes to React Native, such as cleaning up thread blockages. There is no grand solution to performance, and longer-term performance wins will come from incremental instrumentation and improvements. Do not let cognitive bias influence your decisions. Instead, carefully gather and interpret production data to guide future work.

Future plans​

In the long term, we want Marketplace TTI to be comparable to similar products built with Native, and, in general, have React Native performance on par with native performance. Further more, although this half we drastically reduced the bridge startup cost by about 80%, we plan to bring the cost of the React Native bridge close to zero via projects like Prepack and more build time processing.

Β· 8 min read
Tomislav Tenodi

The React Native monthly meeting continues! On this session, we were joined by Infinite Red, great minds behind Chain React, the React Native Conference. As most of the people here were presenting talks at Chain React, we pushed the meeting to a week later. Talks from the conference have been posted online and I encourage you to check them out. So, let's see what our teams are up to.

Teams​

On this second meeting, we had 9 teams join us:

Notes​

Here are the notes from each team:

Airbnb​

Callstack​

  • Mike Grabowski has been managing React Native's monthly releases as always, including a few betas that were pushed out. In particular, working on getting a v0.43.5 build published to npm since it unblocks Windows users!
  • Slow but consistent work is happening on Haul. There is a pull request that adds HMR, and other improvements have shipped. Recently got a few industry leaders to adopt it. Possibly planning to start a full-time paid work in that area.
  • MichaΕ‚ PierzchaΕ‚a from the Jest team has joined us at Callstack this month. He will help maintain Haul and possibly work on Metro Bundler and Jest.
  • Satyajit Sahoo is now with us, yay!
  • Got a bunch of cool stuff coming up from our OSS department. In particular, working on bringing Material Palette API to React Native. Planning to finally release our native iOS kit which is aimed to provide 1:1 look & feel of native components.

Expo​

  • Recently launched Native Directory to help with discoverability and evaluation of libraries in React Native ecosystem. The problem: lots of libraries, hard to test, need to manually apply heuristics and not immediately obvious which ones are just the best ones that you should use. It's also hard to know if something is compatible with CRNA/Expo. So Native Directory tries to solve these problems. Check it out and add your library to it. The list of libraries is in here. This is just our first pass of it, and we want this to be owned and run by the community, not just Expo folks. So please pitch in if you think this is valuable and want to make it better!
  • Added initial support for installing npm packages in Snack with Expo SDK 19. Let us know if you run into any issues with it, we are still working through some bugs. Along with Native Directory, this should make it easy to test libraries that have only JS dependencies, or dependencies included in Expo SDK. Try it out:
  • Released Expo SDK19 with a bunch of improvements across the board, and we're now using the updated Android JSC.
  • Working on a guide in docs with Alexander Kotliarskyi with a list of tips on how to improve the user experience of your app. Please join in and add to the list or help write some of it!
  • Continuing to work on: audio/video, camera, gestures (with Software Mansion, react-native-gesture-handler), GL camera integration and hoping to land some of these for the first time in SDK20 (August), and significant improvements to others by then as well. We're just getting started on building infrastructure into the Expo client for background work (geolocation, audio, handling notifications, etc.).
  • Adam Miskiewicz has made some nice progress on imitating the transitions from UINavigationController in react-navigation. Check out an earlier version of it in his tweet - release coming with it soon. Also check out MaskedViewIOS which he upstreamed. If you have the skills and desire to implement MaskedView for Android that would be awesome!

Facebook​

  • Facebook is internally exploring being able to embed native ComponentKit and Litho components inside of React Native.
  • Contributions to React Native are very welcome! If you are wondering how you can contribute, the "How to Contribute" guide describes our development process and lays out the steps to send your first pull request. There are other ways to contribute that do not require writing code, such as by triaging issues or updating the docs.
    • At the time of writing, React Native has 635 open issues and 249 open pull requests. This is overwhelming for our maintainers, and when things get fixed internally, it is difficult to ensure the relevant tasks are updated.
    • We are unsure what the best approach is to handle this while keeping the community satisfied. Some (but not all!) options include closing stale issues, giving significantly more people permissions to manage issues, and automatically closing issues that do not follow the issue template. We wrote a "What to Expect from Maintainers" guide to set expectations and avoid surprises. If you have ideas on how we can make this experience better for maintainers as well as ensuring people opening issues and pull requests feel heard and valued, please let us know!

GeekyAnts​

  • We demoed the Designer Tool which works with React Native files on Chain React. Many attendees signed up for the waiting list.
  • We are also looking at other cross-platform solutions like Google Flutter (a major comparison coming along), Kotlin Native, and Apache Weex to understand the architectural differences and what we can learn from them to improve the overall performance of React Native.
  • Switched to react-navigation for most of our apps, which has improved the overall performance.
  • Also, announced NativeBase Market - A marketplace for React Native components and apps (for and by the developers).

Infinite Red​

Microsoft​

  • CodePush has now been integrated into Mobile Center. Existing users will have no change in their workflow.
    • Some people have reported an issue with duplicate apps - they already had an app on Mobile Center. We are working on resolving them, but if you have two apps, let us know, and we can merge them for you.
  • Mobile Center now supports Push Notifications for CodePush. We also showed how a combination of Notifications and CodePush could be used for A/B testing apps - something unique to the ReactNative architecture.
  • VS Code has a known debugging issue with ReactNative - the next release of the extension in a couple of days will be fixing the issue.
  • Since there are many other teams also working on React Native inside Microsoft, we will work on getting better representation from all the groups for the next meeting.

Shoutem​

  • Finished the process of making the React Native development easier on Shoutem. You can use all the standard react-native commands when developing apps on Shoutem.
  • We did a lot of work trying to figure out how to best approach the profiling on React Native. A big chunk of documentation is outdated, and we'll do our best to create a pull request on the official docs or at least write some of our conclusions in a blog post.
  • Switching our navigation solution to react-navigation, so we might have some feedback soon.
  • We released a new HTML component in our toolkit which transforms the raw HTML to the React Native components tree.

Wix​

  • We started working on a pull request to Metro Bundler with react-native-repackager capabilities. We updated react-native-repackager to support RN 44 (which we use in production). We are using it for our mocking infrastructure for detox.
  • We have been covering the Wix app in detox tests for the last three weeks. It's an amazing learning experience of how to reduce manual QA in an app of this scale (over 40 engineers). We have resolved several issues with detox as a result, a new version was just published. I am happy to report that we are living up to the "zero flakiness policy" and the tests are passing consistently so far.
  • Detox for Android is moving forward nicely. We are getting significant help from the community. We are expecting an initial version in about two weeks.
  • DetoxInstruments, our performance testing tool, is getting a little bigger than we originally intended. We are now planning to turn it into a standalone tool that will not be tightly coupled to detox. It will allow investigating the performance of iOS apps in general. It will also be integrated with detox so we can run automated tests on performance metrics.

Next session​

The next session is scheduled for August 16, 2017. As this was only our second meeting, we'd like to know how do these notes benefit the React Native community. Feel free to ping me on Twitter if you have any suggestion on how we should improve the output of the meeting.

Β· 6 min read
Tomislav Tenodi

At Shoutem, we've been fortunate enough to work with React Native from its very beginnings. We decided we wanted to be part of the amazing community from day one. Soon enough, we realized it's almost impossible to keep up with the pace the community was growing and improving. That's why we decided to organize a monthly meeting where all major React Native contributors can briefly present what their efforts and plans are.

Monthly meetings​

We had our first session of the monthly meeting on June 14, 2017. The mission for React Native Monthly is simple and straightforward: improve the React Native community. Presenting teams' efforts eases collaboration between teams done offline.

Teams​

On the first meeting, we had 8 teams join us:

We hope to have more core contributors join the upcoming sessions!

Notes​

As teams' plans might be of interest to a broader audience, we'll be sharing them here, on the React Native blog. So, here they are:

Airbnb​

  • Plans to add some A11y (accessibility) APIs to View and the AccessibilityInfo native module.
  • Will be investigating adding some APIs to native modules on Android to allow for specifying threads for them to run on.
  • Have been investigating potential initialization performance improvements.
  • Have been investigating some more sophisticated bundling strategies to use on top of "unbundle".

Callstack​

  • Looking into improving the release process by using Detox for E2E testing. Pull request should land soon.
  • Blob pull request they have been working on has been merged, subsequent pull requests coming up.
  • Increasing Haul adoption across internal projects to see how it performs compared to Metro Bundler. Working on better multi-threaded performance with the Webpack team.
  • Internally, they have implemented a better infrastructure to manage open source projects. Plans to be getting more stuff out in upcoming weeks.
  • The React Native Europe conference is coming along, nothing interesting yet, but y'all invited!
  • Stepped back from react-navigation for a while to investigate alternatives (especially native navigations).

Expo​

Facebook​

  • React Native's packager is now Metro Bundler, in an independent repo. The Metro Bundler team in London is excited to address the needs of the community, improve modularity for additional use-cases beyond React Native, and increase responsiveness on issues and PRs.
  • In the coming months, the React Native team will work on refining the APIs of primitive components. Expect improvements in layout quirks, accessibility, and flow typing.
  • The React Native team also plans on improving core modularity this year, by refactoring to fully support 3rd party platforms such as Windows and macOS.

GeekyAnts​

  • The team is working on a UI/UX design app (codename: Builder) which directly works with .js files. Right now, it supports only React Native. It’s similar to Adobe XD and Sketch.
  • The team is working hard so that you can load up an existing React Native app in the editor, make changes (visually, as a designer) and save the changes directly to the JS file.
  • Folks are trying to bridge the gap between Designers and Developers and bring them on the same repo.
  • Also, NativeBase recently reached 5,000 GitHub stars.

Microsoft​

  • CodePush has now been integrated into Mobile Center. This is the first step in providing a much more integrated experience with distribution, analytics and other services. See their announcement here.
  • VS Code has a bug with debugging, they are working on fixing that right now and will have a new build.
  • Investigating Detox for Integration testing, looking at JSC Context to get variables alongside crash reports.

Shoutem​

  • Making it easier to work on Shoutem apps with tools from the React Native community. You will be able to use all the React Native commands to run the apps created on Shoutem.
  • Investigating profiling tools for React Native. They had a lot of problems setting it up and they will write some of the insights they discovered along the way.
  • Shoutem is working on making it easier to integrate React Native with existing native apps. They will document the concept that they developed internally in the company, in order to get the feedback from the community.

Wix​

  • Working internally to adopt Detox to move significant parts of the Wix app to "zero manual QA". As a result, Detox is being used heavily in a production setting by dozens of developers and maturing rapidly.
  • Working to add support to the Metro Bundler for overriding any file extension during the build. Instead of just "ios" and "android", it would support any custom extension like "e2e" or "detox". Plans to use this for E2E mocking. There's already a library out called react-native-repackager, now working on a PR.
  • Investigating automation of performance tests. This is a new repo called DetoxInstruments. You can take a look, it's being developed open source.
  • Working with a contributor from KPN on Detox for Android and supporting real devices.
  • Thinking about "Detox as a platform" to allow building other tools that need to automate the simulator/device. An example is Storybook for React Native or Ram's idea for integration testing.

Next session​

Meetings will be held every four weeks. The next session is scheduled for July 12, 2017. As we just started with this meeting, we'd like to know how do these notes benefit the React Native community. Feel free to ping me on Twitter if you have any suggestion on what we should cover in the following sessions, or how we should improve the output of the meeting.

Β· 6 min read
Spencer Ahrens

Many of you have started playing with some of our new List components already after our teaser announcement in the community group, but we are officially announcing them today! No more ListViews or DataSources, stale rows, ignored bugs, or excessive memory consumption - with the latest React Native March 2017 release candidate (0.43-rc.1) you can pick from the new suite of components what best fits your use-case, with great perf and feature sets out of the box:

<FlatList>​

This is the workhorse component for simple, performant lists. Provide an array of data and a renderItem function and you're good to go:

<FlatList
data={[{title: 'Title Text', key: 'item1'}, ...]}
renderItem={({item}) => <ListItem title={item.title} />}
/>

<SectionList>​

If you want to render a set of data broken into logical sections, maybe with section headers (e.g. in an alphabetical address book), and potentially with heterogeneous data and rendering (such as a profile view with some buttons followed by a composer, then a photo grid, then a friend grid, and finally a list of stories), this is the way to go.

<SectionList
renderItem={({item}) => <ListItem title={item.title} />}
renderSectionHeader={({section}) => <H1 title={section.key} />}
sections={[ // homogeneous rendering between sections
{data: [...], key: ...},
{data: [...], key: ...},
{data: [...], key: ...},
]}
/>

<SectionList
sections={[ // heterogeneous rendering between sections
{data: [...], key: ..., renderItem: ...},
{data: [...], key: ..., renderItem: ...},
{data: [...], key: ..., renderItem: ...},
]}
/>

<VirtualizedList>​

The implementation behind the scenes with a more flexible API. Especially handy if your data is not in a plain array (e.g. an immutable list).

Features​

Lists are used in many contexts, so we packed the new components full of features to handle the majority of use cases out of the box:

  • Scroll loading (onEndReached).
  • Pull to refresh (onRefresh / refreshing).
  • Configurable viewability (VPV) callbacks (onViewableItemsChanged / viewabilityConfig).
  • Horizontal mode (horizontal).
  • Intelligent item and section separators.
  • Multi-column support (numColumns)
  • scrollToEnd, scrollToIndex, and scrollToItem
  • Better Flow typing.

Some Caveats​

  • The internal state of item subtrees is not preserved when content scrolls out of the render window. Make sure all your data is captured in the item data or external stores like Flux, Redux, or Relay.

  • These components are based on PureComponent which means that they will not re-render if props remains shallow-equal. Make sure that everything your renderItem function depends on directly is passed as a prop that is not === after updates, otherwise your UI may not update on changes. This includes the data prop and parent component state. For example:

    <FlatList
    data={this.state.data}
    renderItem={({item}) => (
    <MyItem
    item={item}
    onPress={() =>
    this.setState(oldState => ({
    selected: {
    // New instance breaks `===`
    ...oldState.selected, // copy old data
    [item.key]: !oldState.selected[item.key], // toggle
    },
    }))
    }
    selected={
    !!this.state.selected[item.key] // renderItem depends on state
    }
    />
    )}
    selected={
    // Can be any prop that doesn't collide with existing props
    this.state.selected // A change to selected should re-render FlatList
    }
    />
  • In order to constrain memory and enable smooth scrolling, content is rendered asynchronously offscreen. This means it's possible to scroll faster than the fill rate and momentarily see blank content. This is a tradeoff that can be adjusted to suit the needs of each application, and we are working on improving it behind the scenes.

  • By default, these new lists look for a key prop on each item and use that for the React key. Alternatively, you can provide a custom keyExtractor prop.

Performance​

Besides simplifying the API, the new list components also have significant performance enhancements, the main one being nearly constant memory usage for any number of rows. This is done by 'virtualizing' elements that are outside of the render window by completely unmounting them from the component hierarchy and reclaiming the JS memory from the react components, along with the native memory from the shadow tree and the UI views. This has a catch which is that internal component state will not be preserved, so make sure you track any important state outside of the components themselves, e.g. in Relay or Redux or Flux store.

Limiting the render window also reduces the amount of work that needs to be done by React and the native platform, e.g from view traversals. Even if you are rendering the last of a million elements, with these new lists there is no need to iterate through all those elements in order to render. You can even jump to the middle with scrollToIndex without excessive rendering.

We've also made some improvements with scheduling which should help with application responsiveness. Items at the edge of the render window are rendered infrequently and at a lower priority after any active gestures or animations or other interactions have completed.

Advanced Usage​

Unlike ListView, all items in the render window are re-rendered any time any props change. Often this is fine because the windowing reduces the number of items to a constant number, but if your items are on the complex side, you should make sure to follow React best practices for performance and use React.PureComponent and/or shouldComponentUpdate as appropriate within your components to limit re-renders of the recursive subtree.

If you can calculate the height of your rows without rendering them, you can improve the user experience by providing the getItemLayout prop. This makes it much smoother to scroll to specific items with e.g. scrollToIndex, and will improve the scroll indicator UI because the height of the content can be determined without rendering it.

If you have an alternative data type, like an immutable list, <VirtualizedList> is the way to go. It takes a getItem prop that lets you return the item data for any given index and has looser flow typing.

There are also a bunch of parameters you can tweak if you have an unusual use case. For example, you can use windowSize to trade off memory usage vs. user experience, maxToRenderPerBatch to adjust fill rate vs. responsiveness, onEndReachedThreshold to control when scroll loading happens, and more.

Future Work​

  • Migration of existing surfaces (ultimately deprecation of ListView).
  • More features as we see/hear the need (let us know!).
  • Sticky section header support.
  • More performance optimizations.
  • Support functional item components with state.

Β· 2 min read
Timothy Yung

At Facebook, we often need to access deeply nested values in data structures fetched with GraphQL. On the way to accessing these deeply nested values, it is common for one or more intermediate fields to be nullable. These intermediate fields may be null for a variety of reasons, from failed privacy checks to the mere fact that null happens to be the most flexible way to represent non-fatal errors.

Unfortunately, accessing these deeply nested values is currently tedious and verbose.

props.user &&
props.user.friends &&
props.user.friends[0] &&
props.user.friends[0].friends;

There is an ECMAScript proposal to introduce the existential operator which will make this much more convenient. But until a time when that proposal is finalized, we want a solution that improves our quality of life, maintains existing language semantics, and encourages type safety with Flow.

We came up with an existential function we call idx.

idx(props, _ => _.user.friends[0].friends);

The invocation in this code snippet behaves similarly to the boolean expression in the code snippet above, except with significantly less repetition. The idx function takes exactly two arguments:

  • Any value, typically an object or array into which you want to access a nested value.
  • A function that receives the first argument and accesses a nested value on it.

In theory, the idx function will try-catch errors that are the result of accessing properties on null or undefined. If such an error is caught, it will return either null or undefined. (And you can see how this might be implemented in idx.js.)

In practice, try-catching every nested property access is slow, and differentiating between specific kinds of TypeErrors is fragile. To deal with these shortcomings, we created a Babel plugin that transforms the above idx invocation into the following expression:

props.user == null
? props.user
: props.user.friends == null
? props.user.friends
: props.user.friends[0] == null
? props.user.friends[0]
: props.user.friends[0].friends;

Finally, we added a custom Flow type declaration for idx that allows the traversal in the second argument to be properly type-checked while permitting nested access on nullable properties.

The function, Babel plugin, and Flow declaration are now available on GitHub. They are used by installing the idx and babel-plugin-idx npm packages, and adding β€œidx” to the list of plugins in your .babelrc file.

Β· 2 min read
Adam Perry

Today we’re announcing Create React Native App: a new tool that makes it significantly easier to get started with a React Native project! It’s heavily inspired by the design of Create React App and is the product of a collaboration between Facebook and Expo (formerly Exponent).

Many developers struggle with installing and configuring React Native’s current native build dependencies, especially for Android. With Create React Native App, there’s no need to use Xcode or Android Studio, and you can develop for your iOS device using Linux or Windows. This is accomplished using the Expo app, which loads and runs CRNA projects written in pure JavaScript without compiling any native code.

Try creating a new project (replace with suitable yarn commands if you have it installed):

$ npm i -g create-react-native-app
$ create-react-native-app my-project
$ cd my-project
$ npm start

This will start the React Native packager and print a QR code. Open it in the Expo app to load your JavaScript. Calls to console.log are forwarded to your terminal. You can make use of any standard React Native APIs as well as the Expo SDK.

What about native code?​

Many React Native projects have Java or Objective-C/Swift dependencies that need to be compiled. The Expo app does include APIs for camera, video, contacts, and more, and bundles popular libraries like Airbnb’s react-native-maps, or Facebook authentication. However if you need a native code dependency that Expo doesn’t bundle then you’ll probably need to have your own build configuration for it. Just like Create React App, β€œejecting” is supported by CRNA.

You can run npm run eject to get a project very similar to what react-native init would generate. At that point you’ll need Xcode and/or Android Studio just as you would if you started with react-native init , adding libraries with react-native link will work, and you’ll have full control over the native code compilation process.

Questions? Feedback?​

Create React Native App is now stable enough for general use, which means we’re very eager to hear about your experience using it! You can find me on Twitter or open an issue on the GitHub repository. Pull requests are very welcome!

Β· 7 min read
Janic Duplessis

For the past year, we've been working on improving performance of animations that use the Animated library. Animations are very important to create a beautiful user experience but can also be hard to do right. We want to make it easy for developers to create performant animations without having to worry about some of their code causing it to lag.

What is this?​

The Animated API was designed with a very important constraint in mind, it is serializable. This means we can send everything about the animation to native before it has even started and allows native code to perform the animation on the UI thread without having to go through the bridge on every frame. It is very useful because once the animation has started, the JS thread can be blocked and the animation will still run smoothly. In practice this can happen a lot because user code runs on the JS thread and React renders can also lock JS for a long time.

A bit of history...​

This project started about a year ago, when Expo built the li.st app on Android. Krzysztof Magiera was contracted to build the initial implementation on Android. It ended up working well and li.st was the first app to ship with native driven animations using Animated. A few months later, Brandon Withrow built the initial implementation on iOS. After that, Ryan Gomba and myself worked on adding missing features like support for Animated.event as well as squash bugs we found when using it in production apps. This was truly a community effort and I would like to thanks everyone that was involved as well as Expo for sponsoring a large part of the development. It is now used by Touchable components in React Native as well as for navigation animations in the newly released React Navigation library.

How does it work?​

First, let's check out how animations currently work using Animated with the JS driver. When using Animated, you declare a graph of nodes that represent the animations that you want to perform, and then use a driver to update an Animated value using a predefined curve. You may also update an Animated value by connecting it to an event of a View using Animated.event.

Here's a breakdown of the steps for an animation and where it happens:

  • JS: The animation driver uses requestAnimationFrame to execute on every frame and update the value it drives using the new value it calculates based on the animation curve.
  • JS: Intermediate values are calculated and passed to a props node that is attached to a View.
  • JS: The View is updated using setNativeProps.
  • JS to Native bridge.
  • Native: The UIView or android.View is updated.

As you can see, most of the work happens on the JS thread. If it is blocked the animation will skip frames. It also needs to go through the JS to Native bridge on every frame to update native views.

What the native driver does is move all of these steps to native. Since Animated produces a graph of animated nodes, it can be serialized and sent to native only once when the animation starts, eliminating the need to callback into the JS thread; the native code can take care of updating the views directly on the UI thread on every frame.

Here's an example of how we can serialize an animated value and an interpolation node (not the exact implementation, just an example).

Create the native value node, this is the value that will be animated:

NativeAnimatedModule.createNode({
id: 1,
type: 'value',
initialValue: 0,
});

Create the native interpolation node, this tells the native driver how to interpolate a value:

NativeAnimatedModule.createNode({
id: 2,
type: 'interpolation',
inputRange: [0, 10],
outputRange: [10, 0],
extrapolate: 'clamp',
});

Create the native props node, this tells the native driver which prop on the view it is attached to:

NativeAnimatedModule.createNode({
id: 3,
type: 'props',
properties: ['style.opacity'],
});

Connect nodes together:

NativeAnimatedModule.connectNodes(1, 2);
NativeAnimatedModule.connectNodes(2, 3);

Connect the props node to a view:

NativeAnimatedModule.connectToView(3, ReactNative.findNodeHandle(viewRef));

With that, the native animated module has all the info it needs to update the native views directly without having to go to JS to calculate any value.

All there is left to do is actually start the animation by specifying what type of animation curve we want and what animated value to update. Timing animations can also be simplified by calculating every frame of the animation in advance in JS to make the native implementation smaller.

NativeAnimatedModule.startAnimation({
type: 'timing',
frames: [0, 0.1, 0.2, 0.4, 0.65, ...],
animatedValueId: 1,
});

And now here's the breakdown of what happens when the animation runs:

  • Native: The native animation driver uses CADisplayLink or android.view.Choreographer to execute on every frame and update the value it drives using the new value it calculates based on the animation curve.
  • Native: Intermediate values are calculated and passed to a props node that is attached to a native view.
  • Native: The UIView or android.View is updated.

As you can see, no more JS thread and no more bridge which means faster animations! πŸŽ‰πŸŽ‰

How do I use this in my app?​

For normal animations the answer is simple, just add useNativeDriver: true to the animation config when starting it.

Before:

Animated.timing(this.state.animatedValue, {
toValue: 1,
duration: 500,
}).start();

After:

Animated.timing(this.state.animatedValue, {
toValue: 1,
duration: 500,
useNativeDriver: true, // <-- Add this
}).start();

Animated values are only compatible with one driver so if you use native driver when starting an animation on a value, make sure every animation on that value also uses the native driver.

It also works with Animated.event, this is very useful if you have an animation that must follow the scroll position because without the native driver it will always run a frame behind of the gesture because of the async nature of React Native.

Before:

<ScrollView
scrollEventThrottle={16}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.animatedValue } } }]
)}
>
{content}
</ScrollView>

After:

<Animated.ScrollView // <-- Use the Animated ScrollView wrapper
scrollEventThrottle={1} // <-- Use 1 here to make sure no events are ever missed
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this.state.animatedValue } } }],
{ useNativeDriver: true } // <-- Add this
)}
>
{content}
</Animated.ScrollView>

Caveats​

Not everything you can do with Animated is currently supported in Native Animated. The main limitation is that you can only animate non-layout properties, things like transform and opacity will work but Flexbox and position properties won't. Another one is with Animated.event, it will only work with direct events and not bubbling events. This means it does not work with PanResponder but does work with things like ScrollView#onScroll.

Native Animated has also been part of React Native for quite a while but has never been documented because it was considered experimental. Because of that make sure you are using a recent version (0.40+) of React Native if you want to use this feature.

Resources​

For more information about animated I recommend watching this talk by Christopher Chedeau.

If you want a deep dive into animations and how offloading them to native can improve user experience there is also this talk by Krzysztof Magiera.

Β· 7 min read
Mengjue (Mandy) Wang

After launching an app to the app stores, internationalization is the next step to further your audience reach. Over 20 countries and numerous people around the world use Right-to-Left (RTL) languages. Thus, making your app support RTL for them is necessary.

We're glad to announce that React Native has been improved to support RTL layouts. This is now available in the react-native master branch today, and will be available in the next RC: v0.33.0-rc.

This involved changing css-layout, the core layout engine used by RN, and RN core implementation, as well as specific OSS JS components to support RTL.

To battle test the RTL support in production, the latest version of the Facebook Ads Manager app (the first cross-platform 100% RN app) is now available in Arabic and Hebrew with RTL layouts for both iOS and Android. Here is how it looks like in those RTL languages:

Overview Changes in RN for RTL support​

css-layout already has a concept of start and end for the layout. In the Left-to-Right (LTR) layout, start means left, and end means right. But in RTL, start means right, and end means left. This means we can make RN depend on the start and end calculation to compute the correct layout, which includes position, padding, and margin.

In addition, css-layout already makes each component's direction inherits from its parent. This means, we simply need to set the direction of the root component to RTL, and the entire app will flip.

The diagram below describes the changes at high level:

These include:

With this update, when you allow RTL layout for your app:

  • every component layout will flip horizontally
  • some gestures and animations will automatically have RTL layout, if you are using RTL-ready OSS components
  • minimal additional effort may be needed to make your app fully RTL-ready

Making an App RTL-ready​

  1. To support RTL, you should first add the RTL language bundles to your app.

  2. Allow RTL layout for your app by calling the allowRTL() function at the beginning of native code. We provided this utility to only apply to an RTL layout when your app is ready. Here is an example:

    iOS:

    // in AppDelegate.m
    [[RCTI18nUtil sharedInstance] allowRTL:YES];

    Android:

    // in MainActivity.java
    I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
    sharedI18nUtilInstance.allowRTL(context, true);
  3. For Android, you need add android:supportsRtl="true" to the <application> element in AndroidManifest.xml file.

Now, when you recompile your app and change the device language to an RTL language (e.g. Arabic or Hebrew), your app layout should change to RTL automatically.

Writing RTL-ready Components​

In general, most components are already RTL-ready, for example:

  • Left-to-Right Layout
  • Right-to-Left Layout

However, there are several cases to be aware of, for which you will need the I18nManager. In I18nManager, there is a constant isRTL to tell if layout of app is RTL or not, so that you can make the necessary changes according to the layout.

Icons with Directional Meaning​

If your component has icons or images, they will be displayed the same way in LTR and RTL layout, because RN will not flip your source image. Therefore, you should flip them according to the layout style.

  • Left-to-Right Layout
  • Right-to-Left Layout

Here are two ways to flip the icon according to the direction:

  • Adding a transform style to the image component:

    <Image
    source={...}
    style={{transform: [{scaleX: I18nManager.isRTL ? -1 : 1}]}}
    />
  • Or, changing the image source according to the direction:

    let imageSource = require('./back.png');
    if (I18nManager.isRTL) {
    imageSource = require('./forward.png');
    }
    return <Image source={imageSource} />;

Gestures and Animations​

In Android and iOS development, when you change to RTL layout, the gestures and animations are the opposite of LTR layout. Currently, in RN, gestures and animations are not supported on RN core code level, but on components level. The good news is, some of these components already support RTL today, such as SwipeableRow and NavigationExperimental. However, other components with gestures will need to support RTL manually.

A good example to illustrate gesture RTL support is SwipeableRow.

Gestures Example​
// SwipeableRow.js
_isSwipingExcessivelyRightFromClosedPosition(gestureState: Object): boolean {
// ...
const gestureStateDx = IS_RTL ? -gestureState.dx : gestureState.dx;
return (
this._isSwipingRightFromClosed(gestureState) &&
gestureStateDx > RIGHT_SWIPE_THRESHOLD
);
},
Animation Example​
// SwipeableRow.js
_animateBounceBack(duration: number): void {
// ...
const swipeBounceBackDistance = IS_RTL ?
-RIGHT_SWIPE_BOUNCE_BACK_DISTANCE :
RIGHT_SWIPE_BOUNCE_BACK_DISTANCE;
this._animateTo(
-swipeBounceBackDistance,
duration,
this._animateToClosedPositionDuringBounce,
);
},

Maintaining Your RTL-ready App​

Even after the initial RTL-compatible app release, you will likely need to iterate on new features. To improve development efficiency, I18nManager provides the forceRTL() function for faster RTL testing without changing the test device language. You might want to provide a simple switch for this in your app. Here's an example from the RTL example in the RNTester:

<RNTesterBlock title={'Quickly Test RTL Layout'}>
<View style={styles.flexDirectionRow}>
<Text style={styles.switchRowTextView}>forceRTL</Text>
<View style={styles.switchRowSwitchView}>
<Switch
onValueChange={this._onDirectionChange}
style={styles.rightAlignStyle}
value={this.state.isRTL}
/>
</View>
</View>
</RNTesterBlock>;

_onDirectionChange = () => {
I18nManager.forceRTL(!this.state.isRTL);
this.setState({isRTL: !this.state.isRTL});
Alert.alert(
'Reload this page',
'Please reload this page to change the UI direction! ' +
'All examples in this app will be affected. ' +
'Check them out to see what they look like in RTL layout.',
);
};

When working on a new feature, you can easily toggle this button and reload the app to see RTL layout. The benefit is you won't need to change the language setting to test, however some text alignment won't change, as explained in the next section. Therefore, it's always a good idea to test your app in the RTL language before launching.

Limitations and Future Plan​

The RTL support should cover most of the UX in your app; however, there are some limitations for now:

  • Text alignment behaviors differ in Android and iOS
    • In iOS, the default text alignment depends on the active language bundle, they are consistently on one side. In Android, the default text alignment depends on the language of the text content, i.e. English will be left-aligned and Arabic will be right-aligned.
    • In theory, this should be made consistent across platform, but some people may prefer one behavior to another when using an app. More user experience research may be needed to find out the best practice for text alignment.
  • There is no "true" left/right

    As discussed before, we map the left/right styles from the JS side to start/end, all left in code for RTL layout becomes "right" on screen, and right in code becomes "left" on screen. This is convenient because you don't need to change your product code too much, but it means there is no way to specify "true left" or "true right" in the code. In the future, allowing a component to control its direction regardless of the language may be necessary.

  • Make RTL support for gestures and animations more developer friendly

    Currently, there is still some programming effort required to make gestures and animations RTL compatible. In the future, it would be ideal to find a way to make gestures and animations RTL support more developer friendly.

Try it Out!​

Check out the RTLExample in the RNTester to understand more about RTL support, and let us know how it works for you!

Finally, thank you for reading! We hope that the RTL support for React Native helps you grow your apps for international audience!