Basic React Native Concepts
ES6
New variable types
let
const
var
NEVER
Sometimes
Always
ES6
// var declaration
function varTest() {
var x = 1
if (true) {
var x = 2 // same variable!
console.log(x) // 2
}
console.log(x) // 2
}
New variable types
- function scoped
// let declaration
function letTest() {
let x = 1
if (true) {
let x = 2 // different variable
console.log(x) // 2
}
console.log(x) // 1
}
var
- global (declared outside any function)
- block-scoped - only available in the block in which they are declared
let
ES6
const key = "mykey"
key = "newkey"
// error "key" is read only
New variable types -
const
- read-only reference to a value
- variable cannot be reassigned
ES6
const person = {
name: "Jennifer",
age: 43,
occupation: "Dentist",
}
person.name = "Jim"
New variable types -
const
{
"age": 43,
"name": "Jim",
"occupation": "Dentist"
}
➡
ES6
Arrow functions
ES5
ES6
var sayName =
function() {}
const sayName =
() => {}
() => {}
this
bound to global
ES6
const getFullName = (first, last) => {
return first + " " + last
}
Functions - implicit vs explicit return
var getFullName = function(first, last) {
return first + " " + last
}
ES5
ES6
const getFullName = (first, last) => first + " " + last
const getFullName = (first, last) =>
first + " " + last
explicit
implicit
explicit
ES6
ES6
const sayName = (name) => console.log("I am " + name + " !")
Arrow functions
Parameters
const sayName = name => console.log("I am " + name + " !")
const addThree = (a, b, c) => a + b + c
ES6
const abc = ["a", "b", "c"]
const def = ["d", "e", "f"]
const alpha = [ ...abc, ...def ]
["a", "b", "c", "d", "e", "f"]
Spread operator
Spread array
const basics = {firstName: "Frank", lastName: "von Hoven"}
const attributes = {job: "Software Engineer"}
const person = {...basics, ...attributes, eyes: "brown"}
{
firstName: "Frank",
lastName: "von Hoven",
job: "Software Engineer",
eyes: "brown"
}
Spread object
...
ES6
const name = person.name
const height = person.height
const location = person.location
console.log(name, height, location)
Object { destructuring }
ES5
const {
name,
height,
location,
sports
} = person
console.log(name, height, location)
ES6
const person = {
name: "Chris",
hairColor: "brown",
height: "6'1",
location: "Portland",
sports: ["football", "tennis"]
}
// "Chris", "6'1", "Portland"
Further Reading
https://github.com/lukehoban/es6features
ES6
JSX
- JSX is a syntax extension, compiled in a preprocessor step that adds XML syntax to JavaScript.
- You can definitely use React without JSX but JSX makes React a lot more elegant.
Candy Time!
JavaScript XML
- For a candy, JSX stands for...
JSX
This:
Compiles to:
<Text color="blue" >
Click Me
</Text>
React.createElement(
Text,
{color: "blue"},
"Click Me"
)
React Native uses JSX
const MyComponent = <Text>Hello World</Text>
const MyImage = <Image source={someSource} style={styleObj} />
{ MyComponent }
{ MyImage }
Embedding Expressions into JSX
const person = { name: "Chris", age: 22 }
const MyComponent = <Text>Hello { person.name }</Text>
Embedding Expressions into JSX
const person = { name: "Chris", age: 22 }
const MyComponent = <Text>Hello { getName() }</Text>
const getName = () => person.name
Logic with JSX
const person = { name: "Chris", age: 22 }
if (person.age >= 20) {
return <Text>{person.name}</Text>
} else {
return <Text>Age is below 20</Text>
}
Logic with JSX
const person = { name: "Chris", age: 22 }
<Text>{person.name} {person.age > 20 ? "Is over 20" : "Is not over 20" }</Text>
ternary operator
JSX Children
<View>
<Text>Hello!</Text>
<Text>Good to see you here.</Text>
</View>
JSX Variables
const greeting = (
<View>
<Text>Hello!</Text>
<Text>Good to see you here.</Text>
</View>
)
// in component
{ greeting }
JSX
- Concise HTML/XML-like structures in the same file as our JavaScript code
- These expressions ➡ actual JavaScript code
tl;dr
- Syntactic sugar
Hello Packing List
- Start new project
- Examine structure
- Create first component
- Pass props
Preview
React Native Core Components
-
View
-
ScrollView
-
Text
-
TextInput
-
Image
-
TouchableOpacity
React Native vs HTML
HTML | React Native |
---|---|
<div> | <View> |
<p> | <Text> |
<input /> | <TextInput /> |
<button> | <TouchableOpacity /> |
Basic React Native Concepts
class MyComponent extends React.Component {
render() {
return (
<Text>Hello World</Text>
)
}
}
class (stateful)
const MyComponent = () => (
<Text>Hello World</Text>
)
<MyComponent />
functional (stateless)
vs
Components ➡ React elements - what should appear on the screen.
Styling
Styles can be created one of three ways:
- inline
- object
- StyleSheet declaration
Styling
inline styles
<Text style={{color: "red"}}>Hello World</Text>
<View style={{width: 300}}>
Styling
style object
const styles = {
text: {
color: "red"
}
}
<Text style={styles.text}>Hello World</Text>
Styling
StyleSheet
import { StyleSheet, View, Text } from "react-native"
const styles = StyleSheet.create({
container: {
width: 300,
height: 130
},
text: {
color: "red"
}
})
<View style={styles.container}>
<Text style={styles.text}>Hello World</Text>
</View>
StyleSheet.create({...})
code
Hello World
- Get app running
- Examine structure
- Create functional component
- Pass props
Re-cap
Step 1
- Able to write to and read from local state
- Introduce local state
Preview
Component State
import React from "react"
import { Text } from "react-native"
class App extends React.Component {
state = { name: "Chris" }
// lifecycle methods
render() {
return (
<Text>{this.state.name}</Text>
)
}
}
class
<App />
- Contains local state
- Lifecycle methods
Basic React Native Components
import React from "react"
import { Text } from "react-native"
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
name: "Chris",
}
}
render() {
return(
<Text>{this.state.name}</Text>
)
}
}
Creating state
Using constructor to declare state
Basic React Native Concepts
import React from "react"
import { View, Text } from "react-native"
class App extends React.Component {
state = { name: "Chris" }
updateName = () => {
this.setState({ name: "Amanda" })
}
render() {
return(
<View>
<Text onPress={this.updateName}>
{this.state.name}
</Text>
</View>
)
}
}
Updating state with
- Component needs to be re-rendered with the updated state
setState
- Enqueues changes to the component state
TextInput
Common props
-
value
-
placeholder
-
onChangeText
(val) => val: string
"string"
-
onSubmitEditing
"string"
() => {}
code
Step 1
- Able to write to and read from local state
- Introduce local state
Re-cap
Step 2
Step 2
- Introduce "items" array into local state
- Move the input to its own function - add a wrapper & buttons
Preview
- Able to push inputted item into the items array
- Able to clear items from the items array
code
Step 2
- Introduce "items" array into local state
- Move the input to its own function - add a wrapper & buttons
Re-cap
- Able to push inputted item into the items array
- Able to clear items from the items array
Step 3
Step 3
- Manipulate controlled component - clear input with ref
- Introduction to controlling a component - TextInput
Preview
- Add more styling - corners & shadows
Refs
Can be assigned one of two ways:
- String
- Callback
ref="myComponent"
ref={(ref) => this.myComponent = ref}
code
Step 3
- Manipulate controlled component - clear input with ref
- Introduction to controlling a component - TextInput
Re-cap
- Add more styling - corners & shadows
Step 4
Step 4
- Intro to FlatList
- Add ability to "check" an item
Preview
FlatList
render() {
const data = [
{ key: "Chris" },
{ key: "Amanda" }
]
return (
<View>
<FlatList
data={data}
renderItem={({ item }) =>
<Text>{item.key}</Text>}
/>
</View>
)
}
Requires 2 props:
-
data
-
renderItem
[ ]
({item}) => { }
FlatList
render() {
const data = [
{ name: "Chris" },
{ name: "Amanda" }
]
renderItem = ({ item }) => {
return <Text>{item.name}</Text>
}
return (
<View>
<FlatList
data={data}
renderItem={this.renderItem}
keyExtractor={item => item.name}
/>
</View>
)
}
keyExtractor
- Key is used for caching
- To track item re-ordering
FlatList
render() {
const data = [
{ name: "Chris" },
{ name: "Amanda" }
]
renderItem = ({ item }) => {
return <Text>{item.name}</Text>
}
return (
<View>
<FlatList
data={data}
renderItem={this.renderItem}
keyExtractor={item => item.name}
ItemSeparatorComponent={() => <View />}
/>
</View>
)
}
ItemSeparatorComponent
FlatList
render() {
const data = [
{ name: "Chris" },
{ name: "Amanda" }
]
renderItem = ({ item }) => {
return <Text>{item.name}</Text>
}
return (
<View>
<FlatList
data={data}
renderItem={this.renderItem}
keyExtractor={item => item.name}
refreshing={this.state.refreshing}
onRefresh={this.onRefresh}
/>
</View>
)
}
onRefresh
code
Step 4
- Intro to FlatList
- Add ability to "check" an item
Re-cap
Step 5
Preview
- Review larger project
- Setup basic project folder structure
- /src/app
- /src/screens
Example Project
Chain React App 2018
- Use this as reference in future
- Be flexible
- Update as you need
- github.com/infinitered/ChainReactApp2018
code
Step 5
Re-cap
- Review larger project
- Setup basic project folder structure
- /src/app
- /src/screens
Step 6
Preview
- Get ready for multiple screens
- Create “components” folder - /components
- Create Button component
- Create ListInput component
code
Step 6
Re-cap
- Get ready for multiple screens
- Create “components” folder - /components
- Create Button component
- Create ListInput component
Step 7
Step 7
- Install React Navigation
Preview
- Pass the items via navigation ➡ input-screen as props
- Create an input-screen.js
- Swap local state for navigation state on packing-list-screen
- Integrate navigation state on input-screen
- Refactoring exercise
Basic React Native Components
-
constructor(props)
-
static getDerivedStateFromProps(nextProps, prevState)
-
render()
-
componentDidMount()
React Lifecycle methods - mounting
Basic React Native Components
-
static getDerivedStateFromProps(nextProps, prevState)
-
render()
-
getSnapshotBeforeUpdate(prevProps, prevState)
-
componentDidUpdate(prevProps, prevState, snapshot)
React Lifecycle methods - mounting
Navigation
react-navigation
The community solution to navigation is a standalone library that allows developers to set up the screens of an app with just a few lines of code.
Navigation
Main types of navigators:
StackNavigator
SwitchNavigator
TabNavigator
DrawerNavigator
Navigation
StackNavigator
npm i react-navigation --save
Step 1: Install react-navigation
yarn add react-navigation
or
Navigation
createStackNavigator
Step 2: import createStackNavigator
import { createStackNavigator } from "react-navigation"
Navigation
Step 3: Create navigation screens using components
const MyHomeRoutes = createStackNavigator({
Home: { screen: Home },
Info: { screen: Info }
},{
initialRouteName: "Info"
}
})
- StackNavigatorConfig: object
- RouteConfigs: object
createStackNavigator takes 2 arguments:
Navigation
Step 4: Render Navigation
AppRegistry.registerComponent("App", () => App)
Navigation
StackNavigator - Basic Implementation
const Home = () => (
<Text>Hello from Home</Text>
)
const Info = () => (
<Text>Hello from Info</Text>
)
const App = StackNavigator({
Home: { screen: Home },
Info: { screen: Info }
})
AppRegistry.registerComponent("App", () => App)
code
Step 7
- Install React Navigation
Re-cap
- Pass the items via navigation ➡ input-screen as props
- Create an input-screen.js
- Swap local state for navigation state on packing-list-screen
- Integrate navigation state on input-screen
- Refactored
Step 8
Preview
- Manage state with Unstated
- https://github.com/jamiebuilds/unstated
Unstated
npm i unstated --save
yarn add unstated
or
Unstated
Unstated gives us 3 things:
- Container class
- Subscribe component
- Provider component
Unstated -
Create container to store state by extending the Container class:
import { Container } from "unstated"
class RootStore extends Container {
// ...
}
export default RootStore
Container
Manage state in the Container using:
import { Container } from "unstated"
class RootStore extends Container {
state = { items: [] }
addItem = item => {
const newItem = { name: item.name, checked: false }
this.setState({ items: [...this.state.items, newItems] })
}
checkItem = selectedItem => {
this.setState({
items: this.state.items.filter(item => {
return item.name === selectedItem.name
? {name: item.name, checked: true }
: item
})
})
}
}
export default RootStore
-
state
-
setState
Unstated -
Container
import { PackingListScreen } from "../screens/packing-list-screen"
import { InputScreen } from "../screens/input-screen"
import { createStackNavigator } from "react-navigation"
import { Provider } from "unstated"
const RootStack = createStackNavigator(
{
Home: PackingListScreen,
Input: InputScreen
}
)
class App extends Component {
render() {
return (
<Provider>
<RootStack />
</Provider>
)
}
}
export default App
-
Stores Container instances
-
Provider's children subscribe to the instances
Unstated -
Provider
import React from "react"
import { Subscribe } from "unstated"
import { RootStore } from "./RootStore"
class MyScreen extends React.Component {
render() {
return (
<View>
<Subscribe to={[RootStore]}>
{rootStore => (
rootStore.items.map(item => <Text>{item.name}</Text>)
)}
</Subscribe>
</View>
)
}
}
-
Function as children
Unstated -
Subscribe
Takes:
- to={[stores]}
&
code
Step 8
Re-cap
- Manage state with Unstated
- https://github.com/jamiebuilds/unstated
Step 9
Step 9
- Persist items in AsyncStorage
Preview
- Bring in AsyncStorage
- Replace Stack Navigator ➡ Tabs Navigator
AsyncStorage
Main methods:
-
setItem
-
multiGet
-
getItem
-
multiSet
AsyncStorage
setItem(key: string, value: string, ?(error) => void)
setItem
getItem(key: string, ?(error, result: ?string) => void)
getItem
setItem("username", "FrankTheTank")
getItem("username", (error, result) => console.log(error, result))
AsyncStorage
multiSet(keyValuePairs: Array<Array<string>>, ?(errors) => void)
multiSet
multiSet(
[
["username", "FrankTheTank"],
["password", "password_snake_cased"]
],
(errors) => console.log(errors)
)
AsyncStorage
multiGet(keys: Array<string>, ?(errors, result: Array<Array<string>>) => void)
multiGet
multiGet(
["username", "password"],
(errors, result) => console.log(result)
)
// [
// ["username", "FrankTheTank"],
// ["password", "password_snake_cased"]
// ]
code
Step 9
- Persist items in AsyncStorage
Re-cap
- Bring in AsyncStorage
- Replace Stack Navigator ➡ Tabs Navigator
Step 10
- Make app match prototype
Preview
- Theme
- Refined Styles - FlexBox
- Styling exercise
- Installing a native module - vector icons
-
react-native link
FlexBox
A component can specify the layout of its children using the flexbox algorithm. Flexbox is designed to provide a consistent layout on different screen sizes.
You will normally use a combination of:
-
flexDirection
-
alignItems
-
justifyContent
to achieve the right layout.
FlexBox
flex: number
container: {
flex: 1
},
box1: {
flex: 1,
backgroundColor: 'red'
},
<View style={styles.container}>
<View style={styles.box1} />
</View>
FlexBox
flex: number
container: {
flex: 1
},
box1: {
flex: 1,
backgroundColor: 'red'
},
box2: {
flex: 1,
backgroundColor: 'orange'
},
<View style={styles.container}>
<View style={styles.box1} />
<View style={styles.box2} />
</View>
FlexBox
flex: number
container: {
flex: 1
},
box1: {
flex: 1,
backgroundColor: 'red'
},
box2: {
flex: 2, // "Change flex from 1 to 2"
backgroundColor: 'orange'
},
<View style={styles.container}>
<View style={styles.box1} />
<View style={styles.box2} />
</View>
FlexBox
flexDirection
container: {
flex: 1
}
<View style={styles.container}>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
</View>
- defines primary axis
- default is column
- column
FlexBox
flexDirection
container: {
flex: 1,
flexDirection: 'row'
}
<View style={styles.container}>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
</View>
- row
FlexBox
justifyContent
Determines the distribution of children along the primary axis.
flexDirection: column
flexDirection: row
⬆
⬇
⬅ ➡
FlexBox
justifyContent:
- flex-start
- center
- flex-end
- space-around
- space-between
FlexBox
justifyContent:
<View style={styles.container}>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
</View>
'center'
container: {
flex: 1,
justifyContent: 'center'
}
container: {
flex: 1,
justifyContent: 'flex-end'
}
container: {
flex: 1
}
'flex-end'
container: {
flex: 1,
justifyContent: "space-around"
}
'space-around'
container: {
flex: 1,
justifyContent: "space-between"
}
'space-between'
FlexBox
alignItems
Determines the distribution of children along the secondary axis.
flexDirection: column
⬆
⟷
⬇
⬅ ↕ ➡
alignItems: center
flexDirection: row
alignItems: center
Default - 'stretch'
horizontal axis
vertical axis
FlexBox
alignItems:
container: {
flex: 1,
alignItems: 'center'
}
'center'
in action
'flex-end'
<View style={styles.container}>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
<Text>Hello World</Text>
</View>
container: {
flex: 1,
alignItems: 'flex-end'
}
code
Step 10
- Make app match prototype
Re-cap
- Theme
- Refined Styles - FlexBox
- Styling exercise
- Installing a native module - vector icons
-
react-native link
Styling + Flexbox
Styling
StyleSheet
import { StyleSheet, View, Text } from ‘react-native'
const styles = StyleSheet.create({
text: {
color: 'red'
},
bigText: {
fontSize: 30
}
})
<Text style={[styles.text, styles.bigText]}>Hello World</Text>
Array of styles
Styling
StyleSheet
import { StyleSheet, View, Text } from ‘react-native'
const styles = StyleSheet.create({
text: {
color: 'red'
}
})
<Text style={[styles.text, { fontSize: 32 } ]}>Hello World</Text>
Combining inline styles with StyleSheet
Styling
Dynamic styling
state = {
warning: true,
}
render() {
const fontColor = this.state.warning ? 'red' : 'black'
return (
<View>
<Text style={{color: fontColor}}>Hello World</Text>
</View>
)
}
Styling
- Styles usually match CSS
backgroundColor
background-color
vs
- Prop names are camelCased
Styling
- width / height - number
Main
non-flex styles
<View/>
- top / left / bottom / right - number
- position - string (absolute, relative)
- padding - number
- margin - number
- borderWidth - number
- borderColor - color
- backgroundColor - color
Basic React Native Concepts
By Infinite Red
Basic React Native Concepts
- 1,807