React Native
Lessons from a year of building apps with
Ryan Boland
ryanboland.com // tanookilabs.com

ryan@tanookilabs.com

@bolandrm (github, twitter)
I’m Ryan Boland
Web Developer

@ Tanooki Labs
Slides
• ??
Goals
• Brief introduction to React Native itself

• Short demo on running a React Native app and
the development loop

• Decide whether React Native would be a good
fit for your project

• Sensible blueprint for starting your own React
Native app
My experience thus far
• Viewer + organizer for
financial research articles

• Ca-Ching! iOS + Android
Getting up to speed
on React Native
No real prerequisites for getting started, but having
someone on the team who is familiar with Xcode
and/or android studio is a huge help
React Native is a framework that allows you to
build native applications with JavaScript and React
import React, { Component } from 'react';
import { Image, ScrollView, Text } from 'react-native';
class ScrollingImageWithText extends Component {
render() {
return (
<ScrollView>
<Image
source={{uri: 'https://i.chzbgr.com/full/7345954048/h7E2C65F9/'}}
style={{width: 320, height:180}}
/>
<Text>
On iOS, a React Native ScrollView uses a native UIScrollView.
On Android, it uses a native ScrollView.
</Text>
</ScrollView>
);
}
}
https://facebook.github.io/react-native/
React Native is
real native
Directory structure
Directory structure
Directory structure
Directory structure
Directory structure
Layout + Styling
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
export default class FlexDirectionBasics extends Component {
render() {
return (
<View style={{flex: 1, flexDirection: 'row'}}>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
</View>
);
}
};
Layout + Styling
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
export default class FlexDirectionBasics extends Component {
render() {
return (
<View style={{flex: 1, flexDirection: 'row'}}>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
</View>
);
}
};
Layout + Styling
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
export default class FlexDirectionBasics extends Component {
render() {
return (
<View style={{flex: 1, flexDirection: 'row'}}>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
</View>
);
}
};
Built-in components
• View, Text, Image, TextInput, ScrollView, StyleSheet

• Button, Picker, Slider, Switch

• FlatList, SectionList

• ActivityIndicator, Alert, CameraRoll, Modal, etc…
Android / iOS specific code
Example: platform specific button.

• Write Android implementation in Button.android.js

• Write iOS implementation in Button.ios.js
import Button from 'Button';
...
Demo!
Why choose
React Native?
Fast Development
• Quick development loop - refresh the app
immediately in most cases (no waiting for
compile)

• The majority of your app’s code will be reused
between Android and iOS

• Take advantage of large JavaScript package
ecosystem
Your team can get
up to speed quickly
• Much of the work can be done by folks with
little native development experience

• Framework is made of simple, easy to use
components
No lock-in
• You can use React Native as much or as little
as you’d like (maybe you just want to use it for
settings or form pages)

• If you have a major component in your app,
you can write it in native code

• If the team outgrows react native, it can be
phased out over time
Discord article -> https://blog.discordapp.com/why-discord-is-sticking-with-react-native-ccc34be0d427
Downsides
• Many different technologies being used
simultaneously

• The build process is more complicated

• Updates can be painful (both React Native and
ios/android updates)

• Android support is lagging a bit
Spinning up your
first React Native
app
There are a lot of
decisions!
Frameworks /
boilerplates
Navigation
Organizing JS
MobX for state!
Airbnb on Redux
“…Redux is notorious for its boilerplate and
has a relatively difficult learning curve. We
provided generators for some common
templates but it was still one of the most
challenging pieces and source of confusion
while working with React Native.”
https://medium.com/airbnb-engineering/react-native-at-airbnb-the-technology-
dafd0b43838
Organizing JS
Component “pods”
// components/index.js and components/Button/index.js
// allow for the following:
import Button from ‘components’
Testing
import React from 'react'
import Button from 'app/components/Button'
import {shallow} from 'enzyme'
describe('Button component', () => {
it('is unclickable, renders with lower opacity with disabled prop', () => {
const wrapper = shallow(
<Button
disabled
text="Disabled"
/>
)
expect(wrapper).toMatchSnapshot()
})
})
Component Snapshot testing
Button.test.js
import React from 'react'
import Button from 'app/components/Button'
import {shallow} from 'enzyme'
describe('Button component', () => {
it('is unclickable, renders with lower opacity with disabled prop', () => {
const wrapper = shallow(
<Button
disabled
text="Disabled"
/>
)
expect(wrapper).toMatchSnapshot()
})
})
Component Snapshot testing
Button.test.js
import React from 'react'
import Button from 'app/components/Button'
import {shallow} from 'enzyme'
describe('Button component', () => {
it('is unclickable, renders with lower opacity with disabled prop', () => {
const wrapper = shallow(
<Button
disabled
text="Disabled"
/>
)
expect(wrapper).toMatchSnapshot()
})
})
Component Snapshot testing
Button.test.js
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Button component is unclickable, renders with lower opacity with disabled prop 1`] = `
<TouchableOpacity
activeOpacity={0.5}
disabled={true}
style={
Array [
Object {
"width": "100%",
},
undefined,
]
}
>
<Component
style={
Array [
Object {
"backgroundColor": "#49718C",
"borderRadius": 2,
"padding": 12,
},
Object {
"opacity": 0.6,
},
Object {},
]
}
>
<inject-Text-with-settings
style={
Array [
Object {
"color": "#FFFFFF",
"fontFamily": "SourceSansPro-SemiBold",
"textAlign": "center",
},
undefined,
]
}
>
Disabled
</inject-Text-with-settings>
</Component>
</TouchableOpacity>
`; Button.test.js.snap
“Golden master testing”
Sharing your App
Purpose Server Distributed via
Debug Local development Staging n/a
Internal
Internal / stakeholder

testing
Staging
Fabric Beta, hockey
app, etc
Beta/QA
Final approval / early
adopter testing
Production
Fabric Beta, hockey
app, etc
Release Release to public Production App Store
App Versions
App identifier -> com.tanookilabs.street-cuts.internal
react-native-device-info allows us to pull out the app
version from the app identifier:
import DeviceInfo from 'react-native-device-info'
export const isRelease = DeviceInfo.getBundleId().split('.').includes('release')
export const isBeta = DeviceInfo.getBundleId().split('.').includes('beta')
export const isInternal = DeviceInfo.getBundleId().split('.').includes('internal')
export const isDebug = DeviceInfo.getBundleId().split('.').includes('debug')
Use react-native-schemes-manager when creating non-
standard versions (e.g. internal/beta)
Continuous Integration
• Tests and linting are run for all pull requests

• Each push to master runs tests, linting, and builds iOS
and android internal version of the app

• Beta and release versions of the apps can be built on
demand
Shipping to the
app stores
Long Term
Maintenance
Update regularly!
https://github.com/ncuillery/rn-diff/
React Native is a game changer
for both developers and their
clients!
Further exploration
• Using CodePush to update production applications
without submitting through the app store processes

• Using TypeScript or Flow to avoid runtime errors
Thanks! Questions?
ryanboland.com // tanookilabs.com

ryan@tanookilabs.com

@bolandrm (github, twitter)
Tanooki Labs
Slides ->

Lessons from a year of building apps with React Native

  • 1.
    React Native Lessons froma year of building apps with Ryan Boland
  • 2.
    ryanboland.com // tanookilabs.com ryan@tanookilabs.com @bolandrm(github, twitter) I’m Ryan Boland Web Developer @ Tanooki Labs
  • 3.
  • 4.
    Goals • Brief introductionto React Native itself • Short demo on running a React Native app and the development loop • Decide whether React Native would be a good fit for your project • Sensible blueprint for starting your own React Native app
  • 5.
    My experience thusfar • Viewer + organizer for financial research articles • Ca-Ching! iOS + Android
  • 6.
    Getting up tospeed on React Native No real prerequisites for getting started, but having someone on the team who is familiar with Xcode and/or android studio is a huge help
  • 7.
    React Native isa framework that allows you to build native applications with JavaScript and React import React, { Component } from 'react'; import { Image, ScrollView, Text } from 'react-native'; class ScrollingImageWithText extends Component { render() { return ( <ScrollView> <Image source={{uri: 'https://i.chzbgr.com/full/7345954048/h7E2C65F9/'}} style={{width: 320, height:180}} /> <Text> On iOS, a React Native ScrollView uses a native UIScrollView. On Android, it uses a native ScrollView. </Text> </ScrollView> ); } } https://facebook.github.io/react-native/
  • 8.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
    Layout + Styling importReact, { Component } from 'react'; import { AppRegistry, View } from 'react-native'; export default class FlexDirectionBasics extends Component { render() { return ( <View style={{flex: 1, flexDirection: 'row'}}> <View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} /> <View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} /> <View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} /> </View> ); } };
  • 16.
    Layout + Styling importReact, { Component } from 'react'; import { AppRegistry, View } from 'react-native'; export default class FlexDirectionBasics extends Component { render() { return ( <View style={{flex: 1, flexDirection: 'row'}}> <View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} /> <View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} /> <View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} /> </View> ); } };
  • 17.
    Layout + Styling importReact, { Component } from 'react'; import { AppRegistry, View } from 'react-native'; export default class FlexDirectionBasics extends Component { render() { return ( <View style={{flex: 1, flexDirection: 'row'}}> <View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} /> <View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} /> <View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} /> </View> ); } };
  • 18.
    Built-in components • View,Text, Image, TextInput, ScrollView, StyleSheet • Button, Picker, Slider, Switch • FlatList, SectionList • ActivityIndicator, Alert, CameraRoll, Modal, etc…
  • 19.
    Android / iOSspecific code Example: platform specific button. • Write Android implementation in Button.android.js • Write iOS implementation in Button.ios.js import Button from 'Button'; ...
  • 20.
  • 21.
  • 22.
    Fast Development • Quickdevelopment loop - refresh the app immediately in most cases (no waiting for compile) • The majority of your app’s code will be reused between Android and iOS • Take advantage of large JavaScript package ecosystem
  • 23.
    Your team canget up to speed quickly • Much of the work can be done by folks with little native development experience • Framework is made of simple, easy to use components
  • 24.
    No lock-in • Youcan use React Native as much or as little as you’d like (maybe you just want to use it for settings or form pages) • If you have a major component in your app, you can write it in native code • If the team outgrows react native, it can be phased out over time Discord article -> https://blog.discordapp.com/why-discord-is-sticking-with-react-native-ccc34be0d427
  • 25.
    Downsides • Many differenttechnologies being used simultaneously • The build process is more complicated • Updates can be painful (both React Native and ios/android updates) • Android support is lagging a bit
  • 26.
    Spinning up your firstReact Native app
  • 27.
    There are alot of decisions!
  • 28.
  • 29.
  • 34.
  • 35.
  • 36.
    Airbnb on Redux “…Reduxis notorious for its boilerplate and has a relatively difficult learning curve. We provided generators for some common templates but it was still one of the most challenging pieces and source of confusion while working with React Native.” https://medium.com/airbnb-engineering/react-native-at-airbnb-the-technology- dafd0b43838
  • 37.
  • 38.
    Component “pods” // components/index.jsand components/Button/index.js // allow for the following: import Button from ‘components’
  • 39.
  • 40.
    import React from'react' import Button from 'app/components/Button' import {shallow} from 'enzyme' describe('Button component', () => { it('is unclickable, renders with lower opacity with disabled prop', () => { const wrapper = shallow( <Button disabled text="Disabled" /> ) expect(wrapper).toMatchSnapshot() }) }) Component Snapshot testing Button.test.js
  • 41.
    import React from'react' import Button from 'app/components/Button' import {shallow} from 'enzyme' describe('Button component', () => { it('is unclickable, renders with lower opacity with disabled prop', () => { const wrapper = shallow( <Button disabled text="Disabled" /> ) expect(wrapper).toMatchSnapshot() }) }) Component Snapshot testing Button.test.js
  • 42.
    import React from'react' import Button from 'app/components/Button' import {shallow} from 'enzyme' describe('Button component', () => { it('is unclickable, renders with lower opacity with disabled prop', () => { const wrapper = shallow( <Button disabled text="Disabled" /> ) expect(wrapper).toMatchSnapshot() }) }) Component Snapshot testing Button.test.js
  • 43.
    // Jest Snapshotv1, https://goo.gl/fbAQLP exports[`Button component is unclickable, renders with lower opacity with disabled prop 1`] = ` <TouchableOpacity activeOpacity={0.5} disabled={true} style={ Array [ Object { "width": "100%", }, undefined, ] } > <Component style={ Array [ Object { "backgroundColor": "#49718C", "borderRadius": 2, "padding": 12, }, Object { "opacity": 0.6, }, Object {}, ] } > <inject-Text-with-settings style={ Array [ Object { "color": "#FFFFFF", "fontFamily": "SourceSansPro-SemiBold", "textAlign": "center", }, undefined, ] } > Disabled </inject-Text-with-settings> </Component> </TouchableOpacity> `; Button.test.js.snap “Golden master testing”
  • 44.
    Sharing your App PurposeServer Distributed via Debug Local development Staging n/a Internal Internal / stakeholder testing Staging Fabric Beta, hockey app, etc Beta/QA Final approval / early adopter testing Production Fabric Beta, hockey app, etc Release Release to public Production App Store
  • 45.
    App Versions App identifier-> com.tanookilabs.street-cuts.internal react-native-device-info allows us to pull out the app version from the app identifier: import DeviceInfo from 'react-native-device-info' export const isRelease = DeviceInfo.getBundleId().split('.').includes('release') export const isBeta = DeviceInfo.getBundleId().split('.').includes('beta') export const isInternal = DeviceInfo.getBundleId().split('.').includes('internal') export const isDebug = DeviceInfo.getBundleId().split('.').includes('debug') Use react-native-schemes-manager when creating non- standard versions (e.g. internal/beta)
  • 46.
    Continuous Integration • Testsand linting are run for all pull requests • Each push to master runs tests, linting, and builds iOS and android internal version of the app • Beta and release versions of the apps can be built on demand
  • 47.
  • 48.
  • 49.
  • 50.
    React Native isa game changer for both developers and their clients!
  • 51.
    Further exploration • UsingCodePush to update production applications without submitting through the app store processes • Using TypeScript or Flow to avoid runtime errors
  • 52.
    Thanks! Questions? ryanboland.com //tanookilabs.com ryan@tanookilabs.com @bolandrm (github, twitter) Tanooki Labs Slides ->