0% found this document useful (0 votes)
24 views

Lec 11

This document provides an overview of React Native including its basic principles, architecture, components, JavaScript development environment setup, creating a new project, adding packages, configuring ESLint, building an initial login view, and using emulators. It covers core RN concepts like Flexbox layout, reusing code across platforms, and state management.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
24 views

Lec 11

This document provides an overview of React Native including its basic principles, architecture, components, JavaScript development environment setup, creating a new project, adding packages, configuring ESLint, building an initial login view, and using emulators. It covers core RN concepts like Flexbox layout, reusing code across platforms, and state management.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 32

React Native

31st Oct 2019

* Slides heavily borrowed from Andres Kavers’ slide deck


RN – basic principle

2
RN - architecture

3
RN – key points
• React Native is a JavaScript framework/library for writing real,
natively rendering iOS, Android and UWP applications.
• Mostly just V part of the application architecture (MVC) paradigm.
• FlexBox layout
• Reuse almost all non-UI code, most UI code among different
platforms
• ES6
• React isn’t framework, it’s a (view)library – state management,
routing, … - up to developer!
4
RN – components - lets get started!

5
RN – js dev environment
• Visual Studio Code (or Atom,….)
• Node and NPM
• npm install -g react-native-cli
• Xcode (if you’re working on a Mac)
• Android Studio

• Dev npm packages


– npm install eslint eslint-plugin-import eslint-plugin-jsx-a11y babel-eslint eslint-config-airbnb
eslint-plugin-react eslint-plugin-react-native --save
• VS Code plugins – F1 - ext install
– react-native
– eslint
6
RN – create new project
• Create RN project
– react-native init demo-project
– cd demo-project
• Prelaunch android emulator from Android Studio
• Close Android Studio, just emulator is needed
– react-native run-ios
– react-native run-android
– Launch Visual Studio Code
– code .
7
RN – packages
• package.json
{
"name": "ContactRN",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"react": "^15.1.0",
"react-native": "^0.28.0"
},
"devDependencies": {
"babel-eslint": "^6.1.0",
"eslint": "^2.13.1",
"eslint-config-airbnb": "^9.0.1",
"eslint-plugin-import": "^1.9.2",
"eslint-plugin-jsx-a11y": "^1.5.3",
"eslint-plugin-react": "^5.2.2",
"eslint-plugin-react-native": "^1.1.0"
}
}
8
"react-native"
],
"rules": {
"indent": [

RN - eslint
],
1,
4

"no-console": 0,
"no-unused-vars": [
1,
• .eslintrc.json {
"vars": "local",
"args": "none"
}
],
"react/forbid-prop-types": 1,
"react/jsx-boolean-value": 1,
"react/jsx-closing-bracket-location": [
1,
{
"selfClosing": "after-props",
"nonEmpty": "after-props"
}
],
"react/jsx-curly-spacing": [
1,
"never",
{
"spacing": {
"objectLiterals": "always"
}
}
],
"react/jsx-indent-props": 1,
"react/jsx-key": 1,
"react/jsx-max-props-per-line": 1,
9
"react/jsx-no-duplicate-props": 1,
RN – VSCode custom settings
• VSCode > Code > Preferences > User Settings

// Place your settings in this file to overwrite the default settings


{
// When opening a file, `editor.tabSize` and `editor.insertSpaces` will be detected based on the file contents.
"editor.detectIndentation": false
}

10
RN – initial view – login screen
• flexbox is used for element positions and scaling
– https://css-tricks.com/snippets/css/a-guide-to-flexbox/
• Typical elements
– View
– Text
– Image
– TextInput
– TouchableHighlight

11
RN – initial view – login screen
• Create new react component
• Keep app code in new directory - app
• Add new file – Login.js

12
import React, { Component } from 'react';
import {

RN – initial view – login


StyleSheet,
Text,
View,
} from 'react-native';

const styles = StyleSheet.create({

• ES6 classes container: {


flex: 1,
justifyContent: 'center',

• Import },
alignItems: 'center',

});
• Styles - flexbox class Login extends Component {

• define class constructor(props) {


super(props);

– constructor(props) this.state = {
};
– this.state for initial state management }

– render() – mandatory render() {


return (
<View style={styles.container}>
• return (..JSX.. markup); <Text>
Login view
– - only one root element </Text>
</View>
• Export class }
);

}
13
module.exports = Login;
RN – initial view – index.*.js
import React, { Component } from 'react';
import {
• Import created module AppRegistry,
StyleSheet,
View,
} from 'react-native';

import Login from './app/Login';


• Use it in view const styles = StyleSheet.create({
container: {
– import Login from './app/Login'; flex: 1,
justifyContent: 'center',
alignItems: 'center',
– <Login/> },
backgroundColor: '#F5FCFF',

});

class ContactRN extends Component {


render() {
return (
<View style={styles.container}>
<Login/>
</View>
);
}
}
14
AppRegistry.registerComponent('ContactRN', () => ContactRN);
RN - emulators

• iOS
– cmd+r for reload
– cmd+d for dev menu
– Enable reload
• Android
– cmd+m for dev menu
– Enable reload

15
RN – design view

 images folder, logo.png


 const logo = require('../images/logo.png');

16
RN – design view

• Elements <View style={styles.container}>


<Image

• this.setState for source={logo}


style={styles.logo} />
<Text style={styles.heading}>
updating state ContactBase Client
</Text>

info
<TextInput
onChangeText={(text) => this.setState({ username: text }) }
placeholder="username"
style={styles.input} />
• {} – for js code <TextInput
onChangeText={(text) => this.setState({ password: text }) }
placeholder="password"
• {{}} - for js objects secureTextEntry
style={styles.input} />
<TouchableHighlight
style={styles.button}>
<Text
style={styles.buttonText}>
Log in
</Text>
</TouchableHighlight> 17
</View>
const styles = StyleSheet.create({
container: {
backgroundColor: '#F5FCFF',

RN – design view
flex: 1,
paddingTop: 60,
alignItems: 'center',
padding: 10,
},
logo: {
width: 194,

• Styles },
height: 65,

heading: {
fontSize: 30,
marginTop: 20,
},
input: {
alignSelf: 'stretch',
height: 50,
marginTop: 10,
padding: 4,
fontSize: 18,
borderWidth: 1,
borderColor: '#48bbec',
},
button: {
height: 50,
backgroundColor: '#48BBEC',
alignSelf: 'stretch',
marginTop: 10,
justifyContent: 'center',
},
buttonText: {
fontSize: 22,
color: '#FFF',
alignSelf: 'center',
},
});
18
RN – es6 and “this”
• ”this” is scoped differently in various JS code parts
• In arrow functions – surrounding class
• Class functions – function itsself
• Bind class scope “this” to function scope in class constructor
– this.someFunction = this.someFunction.bind(this);

19
RN - onPress
class Login extends Component {

constructor(props) {
super(props);
this.onLoginPressed = this.onLoginPressed.bind(this);
this.state = {
};
}

onLoginPressed() {
console.log(`Log in - user:${this.state.username} pass:${this.state.password}`);
console.log(this);
}

render() {
return (
<View style={styles.container}>
<TouchableHighlight
onPress={this.onLoginPressed.bind(this) }
style={styles.button}>
<Text
style={styles.buttonText}>
Log in
</Text>
</TouchableHighlight>
</View>
);
}
} 20
RN – debugging in Chrome

 Dev menu
 Debug JS Remotely
 Open dev console in
Chrome
 Monitor console
 Source code in
debuggerWorker.js tree
 Breakpoints!!!!!

21
RN – state, ActivityIndicator
• Add variable to state – to display ActivityIndicator after button
touch
• Update state in press handler
• RN monitors state (it is special object) and redraws screen on
updates
• Add ActivityIndicator to view

22
RN – state, ActivityIndicator
import React, { Component } from 'react'; class Login extends Component {
import {
ActivityIndicator, constructor(props) {
Image, super(props);
StyleSheet, this.onLoginPressed = this.onLoginPressed.bind(this);
Text, this.state = {
TextInput, showProgress: false,
TouchableHighlight, };
View, }
} from 'react-native';
onLoginPressed() {
console.log(`Log in - user:${this.state.username} pass:${this.state.password}`);
this.setState({ showProgress: true });
}

render() {
return (
<View style={styles.container}>
...
<ActivityIndicator
animating={this.state.showProgress}
hidesWhenStopped
size="large"
style={styles.loader}/>
</View>
);
}
} 23
RN – Rest request (Web API)
• Demo app available on my github
• RN is running on very limited JS engine
• Use Fetch for http requests – promise based
– Note: Errors thrown by rejected Promises need to be caught, or they
will be swallowed silently
fetch('https://mywebsite.com/endpoint.php')
.then((response) => response.text())
.then((responseText) => {
console.log(responseText);
})
.catch((error) => {
console.warn(error);
});
24
RN - AuthService
• OAuth2 Web API token

– Post
• https://servername/Token
– Request headers
• Content-Type: application/x-www-form-urlencoded
– Request body (urlencoded)
• grant_type=password&[email protected]&password=parool

25
RN - AuthService

• Set up info for


class AuthService {
request loginOAuth(credentials, callback) {

• Encode formbody
const loginDetails = {
grant_type: 'password',
username: credentials.username,

• Callback –
password: credentials.password,
};

callback function let formBody = [];

to send info back


Object.keys(loginDetails).forEach((property, index) => {
if ({}.hasOwnProperty.call(loginDetails, property)) {
const encodedKey = encodeURIComponent(property);

to on various const encodedValue = encodeURIComponent(loginDetails[property]);


formBody.push(`${encodedKey}=${encodedValue}`);
}
results });

formBody = formBody.join('&');

const uri = 'https://contacts.akaver.com/Token'; 26


...
RN - AuthService
...
fetch(uri, {
method: 'POST',
headers: {

• Fetch Accept: 'application/json',


'Content-Type': 'application/x-www-form-urlencoded',
},

• Keep track of promises })


body: formBody,

.then((response) => {

• return response; - it if (response.status >= 200 && response.status <= 299) {

}
return response;

gives data over to next console.log(response);


throw { // should be Error object or its derivative
badCredentials: response.status === 400,
method in chain unknownError: response.status !== 400,
statusCode: response.status,
};
})
.then((response) => response.json())
.then((results) => callback({ success: true }))
.catch((error) => callback(error));
}
}

// new it up immediately
module.exports = new AuthService(); 27
RN – using AuthService
render() {
let errorCtrl = <View />;
if (!this.state.success && this.state.badCredentials) {

• Import class errorCtrl = (<Text style={styles.error}>


Bad username/password!
</Text>);
– import authService from }
if (!this.state.success && this.state.unknownError) {

'./AuthService'; errorCtrl = (<Text style={styles.error}>


Unknown error ({this.state.statusCode}) !
</Text>);
}
return (
<View style={styles.container}>
onLoginPressed() { ...
console.log(`Log in - user:${this.state.username} pass:${this.state.password}`); <TouchableHighlight
this.setState({ showProgress: true }); ...
</TouchableHighlight>
authService.loginOAuth({
username: this.state.username, {errorCtrl}
password: this.state.password,
}, (results) => { <ActivityIndicator
this.setState( animating={this.state.showProgress}
// merge objects hidesWhenStopped
Object.assign({ showProgress: false }, results) size="large"
); style={styles.loader}/>
}); </View>
} ); 28
}
RN – navigation in app
• After successful login:
– save auth info (token has to be used on every following request)
– navigate to real app content

• Tabbed layout
• Multiple screens within one Tab
• Provide callbacks for login and logout

29
RN - navigation
• Main view
– IOS
• TabBarIOS and NavigatorIOS  File extension
– Android  BigButton.ios.js
 BigButton.android.js
• DrawerLayoutAndroid
 import BigButton from './components/BigButton';
• Platform detection  Platform module
 var { Platform } = ReactNative;
 Platform.OS === 'ios' ( or 'android')
 var Component = Platform.select({
ios: () => require('ComponentIOS'),
android: () => require('ComponentAndroid'),
})(); 30
RN - Navigation
• Move all logic out of index.*.js
– App.js – analog to Login.js
• App.js
– Add state – isLoggedIn
– Add callback to Login for successful login
• <Login onLogin={this.onLogin.bind(this) } />
– Add onLogin method to App
• onLogin() { this.setState({ isLoggedIn: true }); }
– In render, check for state and select correct component
– Add callback to AppContainer for logout
31
Next week in lab
• Install Android Studio
• Install react-native
• Get my demo app off of github and get it working on your
emulator
• Replace the API I used with the API of your choice to make a
new app

32

You might also like