Gian Marco Toso
Drinking coffee and saving the world. Software Engineer and professional geek
It (mostly) just works!
Gian Marco Toso
@gianmarcotoso
gianmarcotoso
gianmarcotoso.com
polarityb.it
Software Engineer, The One Who Knocks
Software Engineer from Turin, Italy
MSc in Computer Engineering
Researcher and Freelancer
Docker
PHP/Laravel
"It was working on my machine!"
The monolith is here to stay
NodeJS/TypeScript
Seriously, it's awesome!
React + Redux
The Flux Capacitor!
(formerly) iOS/ObjectiveC
and I still get nightmares
Very popular, with a huge market
All the cool kids are developing them 😎
A nightmare to develop
A lot of devices
A lot of resolutions
Different operating systems with different rules
Different programming languages
Write Once, Run Anywhere!
One language (JavaScript)
One runtime environment (the WebView)
Less than ideal UI performance
UI written with ReactJS
Modern JavaScript Code
Native extensions are bridged to JavaScript
UI Components are mapped to native components
Apps written with React Native are real native apps!
import React from 'react'
import { View, Text, AppRegistry } from 'react-native'
class HelloWorld extends React.Component {
render() {
return (
<View style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}}>
<Text style={{fontSize: 72}}>Hello, World!</Text>
</View>
)
}
}
AppRegistry.registerComponent('app', () => HelloWorld)
React Native comes with a command line utility that can be installed with `yarn install react-native-cli`
The CLI tool can be used to create new projects (`react-native init`) or to run them (`react-native run-*`)
In order to run a React Native project on a specific platform, you'll need to have the proper SDK installed!
Inline Styles
Flexbox Algorithm
CSS-Like syntax
Styles can be defined as POJOs
Styles should be defined using the StyleSheet class
import React from 'react'
import { View, Text, StyleSheet } from 'react-native'
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
titleText: {
fontSize: 72
},
red: {
color: 'red'
}
})
const HelloWorld = () => (
<View style={styles.container}>
<Text style={[styles.titleText, styles.red]}>Hello, World!</Text>
</View>
)
export default HelloWorld
React Native has many built-in component to handle common operations
Most components are compatible with both supported platforms
The TouchableHighlight component allows anything to be able to handle touch events
Can be used to wrap most components
Exposes an `onPress` method that receives an Event Handler
import React from 'react'
import { TouchableHighlight, View, Image, Text } from 'react-native'
class TouchableCard extends React.Component {
handleCardTouch = () => {
this.props.onCardTouched()
}
render() {
return (
<View>
<TouchableHighlight onPress={this.handleCardTouch}>
<View>
<Image source={require('image.png')} />
<Text>Some Fancy Image</Text>
</View>
</TouchableHighlight>
</View>
)
}
}
export default TouchableCard
The Modal component can wrap a View and all its content and present it modally whenever required
A Modal will become visible as soon as its visible prop becomes true, and will disappear when it becomes false
It's possible to change the animation used to show the modal by setting the animationType to either fade, slide or none
import React from 'react'
import { View, Modal, Text, Button } from 'react-native'
class ModalContainer extends React.Component {
state = { isModalVisible: false }
render() {
<View>
<Modal visible={this.state.isModalVisible}>
<View>
<Text>Hello, Modal!</Text>
<Button
title="Bye"
onPress={() => this.setState({isModalVisible: false})}
/>
</View>
</Modal>
<Button
title="Open Modal"
onPress={() => this.setState({isModalVisible: true})}
/>
</View>
}
}
The StatusBar component allows to configure the behavior of the mobile OS' status bar
It can be included in any screen in order to have different styles for different pages
import React from 'react'
import { StatusBar, View } from 'react-native'
class MyFancyPage extends React.Component {
render() {
return (
<View>
<StatusBar barStyle="light-content" />
<View>
{/* Page content... */}
</View>
<View>
)
}
}
The ListView component allows to create scrollable views containing items of the same type
The component uses a DataSource to populate itself on every render
It also uses a callback to decide how to render each row, and it's highly configurable
class MyComponent extends Component {
constructor() {
super()
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2})
this.state = {
dataSource: ds.cloneWithRows(['row 1', 'row 2'])
};
}
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => <Text>{rowData}</Text>}
/>
);
}
}
The Navigator Component allows to handle navigation
Navigation is handled through the use or routes and a navigation stack.
When a route is matched, a specific component is returned.
Navigation is handled through the use or routes and a navigation stack.
const routes = [
{ key: 'home', title: 'Home Screen', component: (p) => <Home {...p} /> },
{ key: 'login', title: 'Login', component: (p) => <Login {...p} /> },
]
const Home = ({navigator}) => (
<Button onPress={() => navigator.push('login')} title="Login" />
)
const renderRoute = (route, navigator) => (
routes.find(r => r === route.key)
.component({navigator})
)
const NavigationStack = () => (
<Navigator
initialRoute={routes[0]}
renderScene={renderRoute}
/>
)
export default NavigationStack
The Navigator.NavigationBar allows to create a Navigation Bar, persistent across scenes
It allows to define the Left and Right buttons behavior, as well as the Title
import React from 'react'
import { Navigator, Text, Button } from 'react-native'
const LeftButton = (route, navigator, index, navState) => (
<Button title="Back" onPress={() => navigator.pop()} />
)
const RightButton = (route, navigator, index, navState) => {}
const Title = (route, navigator, index, navState) => (
<Text>{route.title}</Text>
)
const Navbar = () => (
<Navigator.NavigationBar
routeMapper={{
LeftButton,
RightButton,
Title
}}
/>
)
// Passed to the `navigationBar` prop of the `Navigator`
export default Navbar
The Navigator Component is less than ideal
Configuring navigation this way is hard, cumbersome and error prone
You need a way to pass the `navigator` object around if you want to do anything useful
The Navigator component is being deprecated, along with its newer alternative NavigatorExperimental
The official recommended replacement is a third party library called React Navigation
React Native has many built-in modules to handle operations common to mobile devices
Most modules are compatible with both supported platforms
Module actions are called imperatively
The Vibration module makes the phone vibrate using the specified pattern.
The pattern can be repeated any number of times
import { Vibration } from 'react-native'
Vibration.vibrate(
[0, 100], // pattern
1 // repeat
)
The Alert module shows a popup dialog box with confirmation buttons
Each button can have an `onPress` event handler
import { Alert } from 'react-native'
Alert.alert(
'Confirm?'
'Do you confirm this action?',
[
{ title: 'Yes', onPress: () => {} },
{ title: 'No', onPress: () => {}, style: 'cancel' },
]
)
The AppState module tells us if the app is in the background, foreground or inactive state.
It can be listened to by using the addEventListener method
import { AppState } from 'react-native'
let state = 'background'
AppState.addEventListener('change', (newState) => {
state = newState
})
Sometimes it can be useful to know the dimensions of either the screen or the window.
The Dimensions module comes to our aid, by allowing to read dimensions at any time
import { Dimensions } from 'react-native'
const { height, width } = Dimensions.get('window')
const myStyle = {
height, width
}
const myComponent = ({children}) => <View style={myStyle}>{children}</View>
// This will soon be possible (not yet!):
Dimensions.addEventListener('change', ({window, screen}) => {
console.log('new dimensions:', window, screen)
})
A React Native app's code is written in JavaScript
This means you can use most of the libraries you're used to!
Redux
Axios
Fetch
LocalForage
Lodash
RxJS
You'll find many third-party libraries and components online
Some are even recommended by the React Native core team, like AirBnB's `react-native-maps`
Animations are a big part of a Mobile Application's UX
React Native makes animating components somewhat easy with the Animated module
The Animated module exposes replacement components View, Image and Text
These components' style prop can receive instances of the Animated.Value class instead of regular numbers
Animation functions such as timing or spring can be used to animate Animated.Values smoothly
import React from 'react'
import { Text, Animated, Easing } from 'react-native'
const _opacity = new Animated.Value(1)
const changeOpacity = (value = 0) => {
Animated.timing({
toValue: value,
delay: 1000,
easing: Easing.inOut(Easing.ease)
}).start( () => changeOpacity((value + 1) % 2) )
}
class Wobble extends React.Component {
componentDidMount = () => changeOpacity()
render() {
return (
<Animated.View style={{opacity: _opacity}}>
<Text>Wobble!</Text>
</Animated.View>
)
}
}
export default Wobble
Third-party library to render React Native apps inside a web browser
Maps React Native's primitives to standard HTML tags
Allows to debug an App in the browser where possible - there is no support for mobile-specific functionalities!
Not really production ready
Third party module that allows to deploy React Native apps on the Universal Windows Platform
Maps React Native components to native C# primitives
Still under development, YMMV
@gianmarcotoso
By Gian Marco Toso
Slides for my talk at the 2017 FEVR Meetup in Verona
Drinking coffee and saving the world. Software Engineer and professional geek