Quick start# Using Expo# Expo is a framework built on top of React Native that allows you to more easily access native features, like the camera or accelerometer.
Install the Expo CLI: Create new project and boot dev server: Copy expo init AwesomeProject
cd AwesomeProject
npm start
Open App.js
to start editing your app. To run the app on your phone, download the Expo client app on your iOS or Android phone and scan the QR code (for Android) or follow instructions (for iOS).
Components# <View>
# Basically a div
.
<Text>
# Basically a p
.
<Image>
# Like an img
tag on the web, but with different attributes/props. Rather than src
for the image URL, you use the source
prop and pass it an object with a uri
property.
Copy import React , { Component } from 'react' ;
import { Image } from 'react-native' ;
export default class Bananas extends Component {
render ( ) {
let pic = {
uri : 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg'
} ;
return (
< Image source = { pic } style = { { width : 193 , height : 110 } } />
) ;
}
Or you can import the image directly, using Webpack's require()
:
Copy < Image source = { require ( './my-icon.png' ) } />
Also, if you have my-icon.ios.png
and my-icon.android.png
, the packager will pick the correct file for the platform. You can also use the @2x
and @3x
suffixes to provide images for different screen densities.
For example, this would be the structure for this component (<Image source={require('./img/check.png')} />
):
Copy .
├── button . js
└── img
├── check . png
├── check . ios . png
├── check . android . png
├── check@ 2 x . png
└── check@ 3 x . png
<ImageBackground>
# Lets you display an image in the background, similar to the web, since it's not easy to achieve natively. Works similarly as the <Image>
component, but displays children.
Copy return (
< ImageBackground source = { ... } style = { { width : '100%' , height : '100%' } } >
< Text > Inside </ Text >
</ ImageBackground >
) ;
📖Official docs for ImageBackground
<TextInput>
# Basically a input
.
Copy < TextInput
style = { { height : 40 } }
placeholder = " Type here to translate! "
onChangeText = { ( text ) => this . setState ( { text } ) }
value = { this . state . text }
/>
📖 Official docs on <TextInput>
<Button>
# Basically a touch-enabled button
from the web. Uses onPress
instead of onClick
for handling touch events.
Copy < Button
onPress = { ( ) => {
alert ( 'You tapped the button!' ) ;
} }
title = " Press Me "
/>
"Touchable"# Basically like wrapping a <div>
in a <a>
link, but you use these "touchable" components since native doesn't have HTML-style links.
Uses onPress
prop instead of onClick
for handling tap events. If you want to check for a longer tap, use the onLongPress
prop.
<TouchableHighlight>
# Basically like wrapping a <div>
in a <a>
link, but instead you do <TouchableHighlight>
wrapping a <View>
. Makes the <View>
turn lighter when the user presses (and if they hold), letting them know an interaction is occurring.
Copy < TouchableHighlight onPress = { this . _onPressButton } underlayColor = " white " >
< View style = { styles . button } >
< Text style = { styles . buttonText } > TouchableHighlight </ Text >
</ View >
</ TouchableHighlight >
📖Official docs on TouchableHighlight
<TouchableOpacity>
# Reduces the opacity of the content (making it see-through).
Copy < TouchableOpacity onPress = { this . _onPressButton } >
< View style = { styles . button } >
< Text style = { styles . buttonText } > TouchableOpacity </ Text >
</ View >
</ TouchableOpacity >
📖Official docs on TouchableOpacity
<TouchableWithoutFeedback>
# Doesn't show any feedback (like highlight or opacity).
Copy < TouchableWithoutFeedback
onPress = { this . _onPressButton }
>
< View style = { styles . button } >
< Text style = { styles . buttonText } > TouchableWithoutFeedback </ Text >
</ View >
</ TouchableWithoutFeedback >
📖 Official docs on TouchableWithoutFeedback
<TouchableNativeFeedback>
# Creates a ripple effect on Android.
Copy < TouchableNativeFeedback
onPress = { this . _onPressButton }
background = { Platform . OS === 'android' ? TouchableNativeFeedback . SelectableBackground ( ) : '' } >
< View style = { styles . button } >
< Text style = { styles . buttonText } > TouchableNativeFeedback { Platform . OS !== 'android' ? '(Android only)' : '' } </ Text >
</ View >
</ TouchableNativeFeedback >
📖Official docs on TouchableNativeFeedback
<ScrollView>
# Allows you to create scrollable containers (vertical and horizontal) with any child components (text, image, etc). Basically a div
set to overflow: scroll
. Recommended for smaller sets of content, since all components in ScrollView are rendered. FlatList should be used for longer lists (see below).
Copy import React , { Component } from 'react' ;
import { ScrollView , Image , Text } from 'react-native' ;
export default class IScrolledDownAndWhatHappenedNextShockedMe extends Component {
render ( ) {
return (
< ScrollView >
< Text style = { { fontSize : 96 } } > Scroll me plz </ Text >
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Text style = { { fontSize : 96 } } > If you like </ Text >
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Text style = { { fontSize : 96 } } > Scrolling down </ Text >
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Text style = { { fontSize : 96 } } > What's the best </ Text >
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Text style = { { fontSize : 96 } } > Framework around ? </ Text >
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Image source = { { uri : "https://reactnative.dev/img/tiny_logo.png" , width : 64 , height : 64 } } />
< Text style = { { fontSize : 80 } } > React Native </ Text >
</ ScrollView >
) ;
}
}
Copy import React , { useState } from 'react' ;
import { StyleSheet , Image , ScrollView , Text , TextInput , View } from 'react-native' ;
export default function App ( ) {
return (
< ScrollView >
< View style = { { flex : 1 , height : 1000 } } >
< View style = { { flex : 1 , backgroundColor : 'red' } } />
< View style = { { flex : 2 , backgroundColor : 'yellow' } } />
< View style = { { flex : 3 , backgroundColor : 'green' } } />
</ View >
</ ScrollView >
) ;
}
You can allow for paging between ScrollViews (swiping horizontally to go "forward" or "back") by using the pagingEnabled
prop. Swiping horizontally between views can also be implemented on Android using the ViewPager component.
On iOS a ScrollView with a single item can be used to allow the user to zoom content. Set up the maximumZoomScale
and minimumZoomScale
props and your user will be able to use pinch and expand gestures to zoom in and out.
<FlatList>
# Basically a list component that handles virtualization of the list content, meaning only the items currently on the screen are rendered, making it more efficient.
It also allows for scrolling of content, meaning you shouldn't place it inside a <ScrollView>
. The list will take up all the space it needs, and add a scroller. If there's content above or below it, you'll still see a scroll, even though you didn't wrap it all in a <ScrollView>
.
Copy import React , { Component } from 'react' ;
import { FlatList , StyleSheet , Text , View } from 'react-native' ;
export default class FlatListBasics extends Component {
render ( ) {
return (
< View style = { styles . container } >
< FlatList
data = { [
{ key : 'Devin' } ,
{ key : 'Dan' } ,
{ key : 'Dominic' } ,
{ key : 'Jackson' } ,
{ key : 'James' } ,
{ key : 'Joel' } ,
{ key : 'John' } ,
{ key : 'Jillian' } ,
{ key : 'Jimmy' } ,
{ key : 'Julie' } ,
] }
renderItem = { ( { item } ) => < Text style = { styles . item } > { item . key } </ Text > }
/>
</ View >
) ;
}
}
const styles = StyleSheet . create ( {
container : {
flex : 1 ,
paddingTop : 22
} ,
item : {
padding : 10 ,
fontSize : 18 ,
height : 44 ,
} ,
} )
Expo example:
FlatList Basics
<SectionList>
# Same as FlatList, but organizes the list into sections/categories.
Copy import React , { Component } from 'react' ;
import { SectionList , StyleSheet , Text , View } from 'react-native' ;
export default class SectionListBasics extends Component {
render ( ) {
return (
< View style = { styles . container } >
< Text style = { { marginBottom : 30 } } > Header </ Text >
< Text style = { { marginBottom : 30 } } > Header </ Text >
< Text style = { { marginBottom : 30 } } > Header </ Text >
< Text style = { { marginBottom : 30 } } > Header </ Text >
< SectionList
height = { 30 }
sections = { [
{ title : 'D' , data : [ 'Devin' , 'Dan' , 'Dominic' ] } ,
{ title : 'J' , data : [ 'Jackson' , 'James' , 'Jillian' , 'Jimmy' , 'Joel' , 'John' , 'Julie' ] } ,
] }
renderItem = { ( { item } ) => < Text style = { styles . item } > { item } </ Text > }
renderSectionHeader = { ( { section } ) => < Text style = { styles . sectionHeader } > { section . title } </ Text > }
keyExtractor = { ( item , index ) => index }
/>
</ View >
) ;
}
}
const styles = StyleSheet . create ( {
container : {
flex : 1 ,
paddingTop : 22
} ,
sectionHeader : {
paddingTop : 2 ,
paddingLeft : 10 ,
paddingRight : 10 ,
paddingBottom : 2 ,
fontSize : 14 ,
fontWeight : 'bold' ,
backgroundColor : 'rgba(247,247,247,1.0)' ,
} ,
item : {
padding : 10 ,
fontSize : 18 ,
height : 44 ,
} ,
} )
<Modal>
# Allows you to quickly create "modal" like views that pop over the current screen. Modal occupies entire screen, not like a web version that is smaller and shows the page content behind it (maybe darkened).
Copy import React , { Component } from 'react' ;
import { Modal , Text , TouchableHighlight , View , Alert } from 'react-native' ;
export default class ModalExample extends Component {
state = {
modalVisible : false ,
} ;
setModalVisible ( visible ) {
this . setState ( { modalVisible : visible } ) ;
}
render ( ) {
return (
< View style = { { marginTop : 22 } } >
< Modal
animationType = " slide "
transparent = { false }
visible = { this . state . modalVisible }
onRequestClose = { ( ) => {
Alert . alert ( 'Modal has been closed.' ) ;
} } >
< View style = { { marginTop : 22 } } >
< View >
< Text > Hello World ! </ Text >
< TouchableHighlight
onPress = { ( ) => {
this . setModalVisible ( ! this . state . modalVisible ) ;
} } >
< Text > Hide Modal </ Text >
</ TouchableHighlight >
</ View >
</ View >
</ Modal >
< TouchableHighlight
onPress = { ( ) => {
this . setModalVisible ( true ) ;
} } >
< Text > Show Modal </ Text >
</ TouchableHighlight >
</ View >
) ;
}
}
📖Official docs on Modal
<Picker>
# Basically a select
, letting you make a dropdown on Android and iOS.
Copy import * as React from 'react' ;
import { Picker , Text , View , StyleSheet } from 'react-native' ;
import Constants from 'expo-constants' ;
export default class App extends React . Component {
constructor ( props ) {
super ( props ) ;
this . state = {
language : 'JavaScript'
}
}
render ( ) {
return (
< View style = { styles . container } >
< Picker
selectedValue = { this . state . language }
style = { { height : 50 , width : 100 } }
onValueChange = { ( itemValue , itemIndex ) =>
this . setState ( { language : itemValue } )
} >
< Picker.Item label = " Java " value = " java " />
< Picker.Item label = " JavaScript " value = " js " />
</ Picker >
</ View >
) ;
}
}
const styles = StyleSheet . create ( {
container : {
flex : 1 ,
justifyContent : 'center' ,
paddingTop : Constants . statusBarHeight ,
backgroundColor : '#ecf0f1' ,
padding : 8 ,
} ,
} ) ;
<StatusBar>
# Allows you to control the app status bar (top bar on iOS with date, wifi, battery, etc). Doesn't work using Expo on iOS, just hides the bar (which is good for that if needed).
Copy < StatusBar backgroundColor = " blue " bar Style =" light-content " hidden = { isRouteHidden } />
📖Official docs on StatusBar
<Switch>
# A native toggle switch, like a fancy checkbox
component.
Copy import * as React from 'react' ;
import { StyleSheet , Switch } from 'react-native' ;
import Constants from 'expo-constants' ;
export default class App extends React . Component {
constructor ( props ) {
super ( props ) ;
this . state = {
confirmed : false ,
}
}
render ( ) {
return (
< View style = { styles . container } >
< Switch
value = { this . state . confirmed }
onValueChange = { ( itemValue , itemIndex ) =>
this . setState ( { confirmed : itemValue } )
}
/>
</ View >
) ;
}
}
const styles = StyleSheet . create ( {
container : {
flex : 1 ,
justifyContent : 'center' ,
paddingTop : Constants . statusBarHeight ,
backgroundColor : '#ecf0f1' ,
padding : 8 ,
} ,
} ) ;
📖Official docs on Switch
Styling# Styling is accomplished through the style
prop on React Native components. It accepts an object with properties, where the properties are camel-cased CSS properties (e.g. backgroundColor
). You can also pass an array of styles, and the last style will have precedence, allowing you to override style properties (seen in the example below with the last 2 <Text>
components).
You can also isolate and create modular, reusable styles using the StyleSheet.create()
function.
Copy import React , { Component } from 'react' ;
import { StyleSheet , Text , View } from 'react-native' ;
const styles = StyleSheet . create ( {
bigBlue : {
color : 'blue' ,
fontWeight : 'bold' ,
fontSize : 30 ,
} ,
red : {
color : 'red' ,
} ,
} ) ;
export default class LotsOfStyles extends Component {
render ( ) {
return (
< View >
< Text style = { styles . red } > just red </ Text >
< Text style = { styles . bigBlue } > just bigBlue </ Text >
< Text style = { [ styles . bigBlue , styles . red ] } > bigBlue , then red </ Text >
< Text style = { [ styles . red , styles . bigBlue ] } > red , then bigBlue </ Text >
</ View >
) ;
}
}
Number vs string# If you notice in the example above, the fontSize
property is a number, rather than a string value like 24px
. React Native has strict typing for it's styling, meaning you have to use the right type when defining style values. All dimensions in React Native are unitless, and represent density-independent pixels.
Number# fontSize
margin
(as well as marginTop
, etc)padding
(as well as paddingTop
, etc)📖Official docs on styling
Layout# Most of the layout on React Native is accomplished with the flexbox algorithm. By default, layout is similar to display: block;
on the web, where each <View>
component takes up 100% of the width (even if you set a smaller width). By using the flex
property on <View>
components, you can line elements up horizontally, or stack them vertically.
Flexbox works the same way in React Native as it does in CSS on the web, with a few exceptions. The defaults are different, with flexDirection defaulting to column instead of row, and the flex parameter only supporting a single number.
Vertical boxes# Copy import React , { Component } from 'react' ;
import { View } from 'react-native' ;
export default class FlexDirectionBasics extends Component {
render ( ) {
return (
< View style = { { flex : 1 , flexDirection : 'row' } } >
< View style = { { flex : 1 , backgroundColor : 'red' } } />
< View style = { { flex : 2 , backgroundColor : 'yellow' } } />
< View style = { { flex : 3 , backgroundColor : 'green' } } />
</ View >
) ;
}
} ;
In the following example the red, yellow and the green views are all children in the container view that has flex: 1
set. The red view uses flex: 1
, the yellow view uses flex: 2
and the green view uses flex: 3
. 1+2+3 = 6
which means that the red view will get 1/6
of the space, the yellow 2/6
of the space and the green 3/6
of the space.
Horizontal boxes# Copy import React , { Component } from 'react' ;
import { 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 >
) ;
}
} ;
📖Official docs on flexbox
📖Official docs on Yoga - the layout engine behind React Native
Input# Works the same as React. You defer control of the form to React state and make sure the input reflects the React state.
Class version# Copy import React , { Component } from 'react' ;
import { Text , TextInput , View } from 'react-native' ;
export default class PizzaTranslator extends Component {
constructor ( props ) {
super ( props ) ;
this . state = { text : '' } ;
}
render ( ) {
return (
< View style = { { padding : 10 } } >
< TextInput
style = { { height : 40 } }
placeholder = " Type here to translate! "
onChangeText = { ( text ) => this . setState ( { text } ) }
value = { this . state . text }
/>
< Text style = { { padding : 10 , fontSize : 42 } } >
{ this . state . text . split ( ' ' ) . map ( ( word ) => word && '🍕' ) . join ( ' ' ) }
</ Text >
</ View >
) ;
}
}
Hooks version# Copy import React , { useState } from 'react' ;
import { StyleSheet , Text , TextInput , View } from 'react-native' ;
export default function App ( ) {
const [ formText , setFormText ] = useState ( "" ) ;
return (
< View style = { styles . container } >
< TextInput
placeholder = " Enter text here... "
onChangeText = { ( text ) => setFormText ( text ) }
value = { formText }
/>
< Text style = { styles . formText } > Form text : { formText } </ Text >
</ View >
) ;
}
const styles = StyleSheet . create ( {
container : {
flex : 1 ,
backgroundColor : '#fff' ,
alignItems : 'center' ,
justifyContent : 'center' ,
} ,
formText : {
fontSize : 18 ,
marginTop : 20 ,
}
} ) ;
Handling touches# Wrap <View>
components in "touchable" components, like <TouchableHighlight>
. See components for more info on which to use when.
📖Official docs on touches
Data fetching# React Native allows you to use fetch()
like modern browsers. Just use it in your code, no need to import it from anywhere.
Copy import React from 'react' ;
import { FlatList , ActivityIndicator , Text , View } from 'react-native' ;
export default class FetchExample extends React . Component {
constructor ( props ) {
super ( props ) ;
this . state = { isLoading : true }
}
componentDidMount ( ) {
return fetch ( 'https://reactnative.dev/movies.json' )
. then ( ( response ) => response . json ( ) )
. then ( ( responseJson ) => {
this . setState ( {
isLoading : false ,
dataSource : responseJson . movies ,
} , function ( ) {
} ) ;
} )
. catch ( ( error ) => {
console . error ( error ) ;
} ) ;
}
render ( ) {
if ( this . state . isLoading ) {
return (
< View style = { { flex : 1 , padding : 20 } } >
< ActivityIndicator />
</ View >
)
}
return (
< View style = { { flex : 1 , paddingTop : 20 } } >
< FlatList
data = { this . state . dataSource }
renderItem = { ( { item } ) => < Text > { item . title } , { item . releaseYear } </ Text > }
keyExtractor = { ( { id } , index ) => id }
/>
</ View >
) ;
}
}
By default, iOS will block any request that's not encrypted using SSL . If you need to fetch from a cleartext URL (one that begins with http
) you will first need to add an App Transport Security exception . If you know ahead of time what domains you will need access to, it is more secure to add exceptions only for those domains; if the domains are not known until runtime you can disable ATS completely . Note however that from January 2017, Apple's App Store review will require reasonable justification for disabling ATS . See Apple's documentation for more information.
Using Other Networking Libraries# The XMLHttpRequest API is built into React Native. This means that you can use third party libraries such as frisbee or axios that depend on it, or you can use the XMLHttpRequest API directly if you prefer.
Copy var request = new XMLHttpRequest ( ) ;
request . onreadystatechange = ( e ) => {
if ( request . readyState !== 4 ) {
return ;
}
if ( request . status === 200 ) {
console . log ( 'success' , request . responseText ) ;
} else {
console . warn ( 'error' ) ;
}
} ;
request . open ( 'GET' , 'https://mywebsite.com/endpoint/' ) ;
request . send ( ) ;
The security model for XMLHttpRequest is different than on web as there is no concept of CORS in native apps.
WebSocket Support# React Native also supports WebSockets , a protocol which provides full-duplex communication channels over a single TCP connection.
Copy var ws = new WebSocket('ws://host.com/path');
ws.onopen = () => {
// connection opened
ws.send('something'); // send a message
};
ws.onmessage = (e) => {
// a message was received
console.log(e.data);
};
ws.onerror = (e) => {
// an error occurred
console.log(e.message);
};
ws.onclose = (e) => {
// connection closed
console.log(e.code, e.reason);
};
Known Issues with fetch
and cookie based authentication# The following options are currently not working with fetch
redirect:manual
credentials:omit
Having same name headers on Android will result in only the latest one being present. A temporary solution can be found here: https://github.com/facebook/react-native/issues/18837#issuecomment-398779994 . Cookie based authentication is currently unstable. You can view some of the issues raised here: https://github.com/facebook/react-native/issues/23185 As a minimum on iOS, when redirected through a 302
, if a Set-Cookie
header is present, the cookie is not set properly. Since the redirect cannot be handled manually this might cause a scenario where infinite requests occur if the redirect is the result of an expired session.