Basic React

Welcome

Connect

community.infinite.red

#campminder-training

Frank

von Hoven

  • Senior Software Engineer

  • React Native Newsletter

    • ​Editor-in-Chief​

Ryan Linton

  • Señor Software Engineer

  • Master of the Serious

Intro to JavaScript

A brief history...

  • 1995 - Created at Netscape by Brendan Eich
  • early 1996 - First released with Netscape 2
  • mid 1996 - Microsoft releases JScript with IE 3
  • late 1996 - Netscape submits JavaScript to ECMA International, resulting in the first edition of the ECMAScript standard (i.e. ES1)
  • 1999 - ES3, a significant update to the standard is released, stable ever since
  • 1999-2009 - ES4 started and abandoned
  • 2009 - ES5 released
  • 2015 - ES6/ES2015 released, yearly release cycle adopted

Types

  • Number
  • String
  • Boolean
  • Symbol (new in ES6/ES2015)
  • Object
    • Function
    • Array
    • Date
    • RegExp
  • null
  • undefined

Numbers

  • double-precision 64-bit format IEEE 754 values

  0.1 + 0.2 // 0.30000000000000004
  • standard arithmetic operators are supported

  1 - 2 + 3 * 4 / 5 % 6 // 1.4
  • convert strings to integers using parseInt()

  parseInt('123', 10)   // 123
  parseInt('010', 10)   // 10
  parseInt('hello', 10) // NaN (i.e. Not a Number)
  • special values for NaN, Infinity, -Infinity

  NaN + 5            // NaN
  NaN === NaN        // false
  isNaN(NaN)         // true
  1 / 0              // Infinity
  -1 / 0             // -Infinity
  isFinite(Infinity) // false

Strings

  • sequences of UTF-16 code units
  • each unicode character is represented by either 1 or 2 code units

  "\u03BB" === "λ"
  "\uD83D\uDC10" === "🐐"
  • can be used like objects with many properties and methods to explore

  "react".length        // 5
  "react".charAt(0)     // "r"
  "react".toUpperCase() // "REACT"
  "hello, world".replace("world", "react") // "hello, react"

Other Types

  • null indicates a deliberate non-value
  • undefined indicates an uninitialized variable

  null !== undefined // true

The following values are falsey


  Boolean(false)     // false
  Boolean(0)         // false
  Boolean("")        // false
  Boolean(NaN)       // false
  Boolean(null)      // false
  Boolean(undefined) // false

All other values are truthy

Operators & Control Structures

Similar set of operators and control structures to other languages in the C family


  // logical operators
  true && false || 0 // 0
  
  // conditional statements
  if (true && 1) {
    // always executed
  } else if(false || 0) {
    // never executed
  } else {
    // also never
  }

  // ternary operator
  true 
    ? "an expression" 
    : "" // "an expression"

  // while loops
  while(true) { /* loop forever */ }
  do { 
    /* execute once; loop never */ 
  } while(false)

  // for loops
  for (let i = 0; i < 5; i++) {
    // execute 5 times
  }
  for (let value of [1,2,3]) {
    // do something with value
  }
  for (let property in { key: 'value' }) {
    // do something with object property
  }
  

Objects

  • can be thought of as simple collections of name-value pairs
  • Similar to Hash tables in C and C++,  HashMaps in Java, or Dictionaries in Python
  
  // create using the new keyword
  new Object()

  // or literal
  let obj = {
    name: "Mappy",
    role: "associates stuff"
  }

  // access with brackets
  obj["name"] // "Mappy"

  // or dot notation
  obj.role // "associates stuff"

  // a prototype
  function Person(name, age) {
    this.name = name;
    this.age = age;
  }

  // an instance
  const frank = new Person("Frank", 38)

  // ES6 adds the following sugar
  class Frank extends Person {
    constructor(props) {
      super(props)
    }
  }

Arrays

  • actually a special type of object
  • work very much like regular objects (numerical properties can naturally be accessed only using [] syntax) but they have one magic property called 'length'

  // create with new
  const a = new Array()
  
  // or literal syntax
  const snacks = ["tacos","nachos","cheetos"]

  // iterate with for loop
  for(const snack of snacks) {
    eat(snack)
  }

  // or with an iterator method
  snacks.map(function(snack) {
    return snack.toUpperCase()
  })

Functions

ES6 / ES2015

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: "Boulder",
  sports: ["football", "tennis"]
}
// "Chris", "6'1", "Boulder"

ES6

const lettuce = toppings[0]
const pickles = toppings[1]



console.log(lettuce, pickles)

Array [ destructuring ]

ES5

const [lettuce, pickles] = toppings
// destructure toppings by index



console.log(lettuce, pickles)

ES6

const toppings = [
  "lettuce",
  "pickles",
  "tomatoes",
  "onions"
]
// "lettuce", "pickles"

Further Reading

https://github.com/lukehoban/es6features

ES6

JSX

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.

JSX

This:

Compiles to:

<p style={{ color: "blue" }}>
  Click Me
</p>
React.createElement(
 "p",
  {style: { color: "blue"}},
  "Click Me"
)

React & React Native use JSX

const MyComponent = <p>Hello World</p>
const MyImage = <img src={someSource} style={styleObj} />
<MyComponent/>


<MyImage/>

Use in JSX like this:

Embedding Expressions into JSX

const person = { name: "Chris", age: 22 }
const MyComponent = <p>Hello { person.name }</p>

Embedding Expressions into JSX

const person = { name: "Chris", age: 22 }
const MyComponent = <p>Hello { getName() }</p>
const getName = () => person.name 

Logic with JSX

renderLegalPerson = () => {
  const person = { name: "Chris", age: 22 }
  if (person.age >= 20) {
    return <p>{person.name}</p>
  } else {
    return <p>Age is below 20</p>
  }
}


...

<div>
  { this.renderLegalPerson() }
</div>

...

Logic with JSX

const person = { name: "Chris", age: 22 }

<p>{person.name} { person.age > 20 ? "Is over 20" : "Is not over 20" }</p>

ternary operator

JSX

  • Concise HTML/XML-like structures in the same file as our JavaScript code

 

  • These expressions ➡ actual JavaScript code

tl;dr

  • Syntactic sugar

React Philosophy

What is React?

  • Declarative
    • "Make me a sandwich"
  • Component-Based
    • Encapsulated components that manage their own state
      •  Compose them to make complex UIs.
    • Building blocks to make your app
  • Learn Once, Write Anywhere
    • Use React on the web and on mobile - React Native

UI Framework

Hello World

  • Create first component
  • Pass props

Preview

Basic React Concepts

"Components"

class MyComponent extends React.Component {
  render() {
    return (
     <p>Hello World</p>
    )
  }
}

Class

const MyComponent = () => (
  <p>Hello World</p>
)
<MyComponent />

Function

vs

Components React elements - what should appear on the screen.

Styling

Styles can be created one of three ways:

  • inline
  • object  
  • CSS

Styling

inline styles

<p style={{color: "red"}}>Hello World</p>

<div style={{width: 300}}/>

Styling

style object

const styles = {
  text: {
    color: "red"
  }
}

<p style={styles.text}>Hello World</p>

Styling

...

const styles = {
 text: {
    color: 'red'
  }
}

<p style={[styles.text, { fontSize: 32 } ]}>Hello World</p>

Combining inline styles with style object

with an array of styles

Styling

Dynamic styling

state = {
  warning: true
}

...

render() {
  const fontColor = this.state.warning ? 'red' : 'black'
  return (
    <div>
      <p style={{color: fontColor}}>Hello World</p>
    </div>
  )
}

Styling

  • Styles usually match CSS
backgroundColor
background-color

vs

  • Prop names are camelCased

Styling

CSS
import "./styles.css"

... 

<div className="container">
  <p className="funText">Hello World</p>
</div>


...


// in styles.css

.container {
  text-align: center;
}

.funText {
  color: fuchsia;
  font-size: 100px;
}

code

Kid Counter

with React Component

  • Introduce local state
  • Able to write to and read from local state
  • Intro to component lifecycle

Preview

Basic React Concepts

import React from "react"

class App extends React.Component {
  state = { name: "Chris" }

// lifecycle methods

  render() {
    return (
     <p>{this.state.name}</p>
    )
  }
}

class

<App />
  • Contains local state  
  • Lifecycle methods

Basic React Concepts

import React from "react"

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      name: "Chris"
    }
  }

  render() {
    return(
      <p>{this.state.name}</p>
    )
  }
}

Creating state

Using constructor to declare state

Basic React Concepts

import React from "react"

class App extends React.Component {
  state = { name: "Chris" }

  updateName = () => {
    this.setState({ name: "Amanda" })
  }

  render() {
    return(
      <div>
        <p onClick={this.updateName}>
          {this.state.name}
        </p>
      </div>
    )
  }
}

Updating state with

  • Component needs to be re-rendered with the updated state
setState
  • Enqueues changes to the component state

Basic React Concepts

Frequently Used React Lifecycle methods

code

Kid Counter

 Function Component

Hooks!

Hooks!

  • Lets you use state and other React features without writing a class
  • Functions that let you “hook into” React state and lifecycle features from function components
  • Don’t work inside classes — they let you use React without classes

useState()

  • Allows you to use state in a functional component
  • Can declare only one state variable at a time
  • Able to set an initial state as an argument
  • Use array destructuring to retrieve the value and setter
const [count, setCount] = useState(0)

How does it work???

It's just closures...


function useState(initialValue) {

  let _val = initialValue      // _val is a local variable created by useState

  function state() {           // state is an inner function, a closure
    return _val            
  }

  function setState(newVal) {  // setState is also a closure 
    _val = newVal                
  }

  return [state, setState]     // exposing functions for external use
}

const [foo, setFoo] = useState(0) // using array destructuring

console.log(foo())   // 0 - the initialValue we gave

setFoo(1)            // sets _val inside useState's scope

console.log(foo())   // 1 - new initialValue, despite exact same call

...and arrays


const MyReact = (function() {
  let hooks = [],
      currentHook = 0 // array of hooks, and an iterator!

  return {
    render(Component) {
      const Comp = Component() // run effects
      Comp.render()
      currentHook = 0 // reset for next render
      return Comp
    },

    useState(initialValue) {
      hooks[currentHook] = hooks[currentHook] || initialValue
      const setStateHookIndex = currentHook // for setState's closure!
      const setState = newState => (hooks[setStateHookIndex] = newState)
      return [hooks[currentHook++], setState]
    }
  }
})() // MyReact is an IIFE (moar closures!!!)
code

Create a list of camps

map()

  • Creates a new array
  • With the results of calling a provided function
  • On every element in the calling array.

map()

[1, 2, 3]

Array     →

[1, 2, 3].map()

.map()   →

[1, 2, 3].map((item) => item)

.map()   →

[1, 2, 3].map((item, index) => item + index)

.map()   →

[1, 2, 3]

returns →

[1, 3, 5]

returns →

map()

const items = [{name: "Nick"}, {name: "Bill"}, {name: "Steve"}]
items.map((item) => ?)

Bill

Nick

Steve

items.map((item) => <p>{item.name}</p>)
code

Create a CampDetailsScreen

Make new component in App.js and export it

export default App // currently exporting App




// 1) create new "Screen"
const CampDetailsScreen = () => {
  return (
    //  Your code Here
  )
}

// 2) export default the new screen - "CampDetailsScreen"



export default CampDetailsScreen // in App.js you should have this now


Build this on your own 👍🤞

Navigation

react-navigation

Navigation

npm i @react-navigation/web --save

Step 1: Install react-navigation

npm i @react-navigation/core --save

Navigation

createSwitchNavigator

Step 2: import createSwitchNavigator

// App.js

import { createSwitchNavigator } from "@react-navigation/core"

Navigation

createBrowserApp

Step 3: import createBrowserApp

// App.js

import { createBrowserApp } from "@react-navigation/web"

Navigation

Step 4: Create navigation screens using components

import { HomeScreen } from "./screens/HomeScreen"
import { InfoScreen } from "./screens/InfoScreen"

...

const MyHomeRoutes = createSwitchNavigator(
  { 
    Home: HomeScreen,          // routes
    Info: InfoScreen
  },
  { initialRouteName: "Info" } // configuration
)

createSwitchNavigator takes 2 arguments:

Navigation

Step 5: Render Navigation

// in App.js

...

const AppNavigator = createSwitchNavigator({
  camps: CampListScreen,
  camp: CampDetailsScreen,
})

const App = createBrowserApp(AppNavigator)

export default App
code

Make Components

  • <Tile/> - CampListScreen

  • <Header/> - App-wide

  • <Footer/> - App-wide

Login Screen

Login Screen

  • Controlled vs uncontrolled component
  • Toggle password visibility with useRef
code

Registration Screen

localStorage

💾

localStorage

Main methods:

  • setItem
  • clear
  • getItem
  • removeItem

localStorage

Main methods:

  • setItem("key", "value")
  • clear()
  • getItem("key")
  • removeItem("key")
code

Feed Screen

withNavigation HOC

Post Modal

Cart Screen

MobX State Tree

MST

Overview

  • Opinionated - How data should be structured and updated

  • Typed — Includes its own typed API

  • Models — You build trees of models

MST

Common typings of types:

  • types.string
  • types.number
  • types.boolean
  • types.array(type)

MST

Uses Observers

  • Page/Screen
    • observe/listen/subscribe to MST state
    • facilitates state changes in MST state

Observers allow:

MST

Setup model (store)

import { types } from "mobx-state-tree"

const RootStore = types.model({
  userId: types.string
})

...

MST

Add some actions

import { types } from "mobx-state-tree"

const RootStore = types.model({
  userId: types.string
})
.actions(self => ({
  setUserId(id) {
    self.userId = id
  }
}))


...

MST

Create the store!

import { types } from "mobx-state-tree"

const RootStore = types.model({
  userId: types.string
})
.actions(self => ({
  setUserId(id) {
    self.userId = id
  }
}))


export const store = RootStore.create()

Context API

  • Alternative to prop drilling
  • Designed to share data that can be considered “global” for a tree of React components
const defaultValue = "so contextual"

// create the context
const MyContext = React.createContext(defaultValue)

// provide in a top level component
render() {
  return ( 
    <MyContext.Provider value={"so contextual"}>
      {children}
    </MyContext>
  )
}

// use in a component
const context = useContext(MyContext)

context === "so contextual"

Purchases Screen

Testing

Unit Tests

Test individual parts (e.g. functions, objects) to ensure they interface and work as expected

Characteristics of good unit tests

  • Free of dependencies or side effects
  • Fast
  • Thorough
  • Well factored

Component Tests

Test individual React components apart from where they are used in the application

  • Create an instance of the component
  • Pass it different props
  • Interact with it and see how it behaves

Snapshot Tests

Test that components have not changed by comparing snapshots of the React tree

  • Quickest and easiest tests to write
  • Break frequently
  • Easy to update
  • Need to be written after implementation (i.e. no TDD)
  • Powerful in combination with Storybook

End-to-End Tests

Test your entire application the way a user would, simulating clicks and checking for components on the screen

  • Provide the greatest confidence that your application is working as expected
  • Slow
  • Difficult to write and maintain
  • Test failures are often difficult to diagnose
code

Next Steps

Be Free!

Next Steps

  • show subtotals and totals for purchases

  • actually protect routes

  • change price based on size

  • highlight active route in nav bar

  • better styles

  • animations

  • write more tests

React Native

Let's Shift Gears

Main Differences

  • JSX - TitleCased vs lowercase & imported
  • FlatList vs map - list components
  • ScrollView - required to scroll
  • Navigation - stack & tab navigators
  • FlexBox - used by default
  • AsyncStorage vs localStorage

React Native Core Components

  • View
  • ScrollView
  • Text
  • TextInput
  • Image
  • TouchableOpacity

React vs React Native

React React Native
<div> <View>
<p> <Text>
<input /> <TextInput />
<button> <TouchableOpacity />

Styling

Styles can be created one of three ways:

  • inline
  • object  
  • StyleSheet declaration

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({...})

Expo App

CampsListScreen

FlatList

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

CampDetailsScreen

React Navigation in React Native

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

npm i react-navigation --save

Step 1: Install react-navigation

yarn add react-navigation

or

Navigation

npm i react-native-gesture-handler --save

Step 1a: Install react-native-gesture-handler

yarn add react-native-gesture-handler

or

Navigation

Step 1b: Link react-native-gesture-handler

react-native link react-native-gesture-handler

Navigation

createStackNavigator

Step 2: import createStackNavigator

import { createStackNavigator } from "react-navigation"

Step 3: import createAppContainer

import { createStackNavigator, createAppContainer } from "react-navigation"

Navigation

createAppContainer
  • Containers are responsible for managing your app state and linking your top-level navigator to the app environment
  • On Android, the app container uses the Linking API to handle the back button
  • The container can also be configured to persist your navigation state
  • Props of createAppContainer

Navigation

Step 4: Create navigation screens using components

const MyHomeRoutes = createStackNavigator({
  Home: { screen: Home },
  Info: { screen: Info }
},{
  initialRouteName: "Home"
  }
})
  •  StackNavigatorConfig: object
  •  RouteConfigs: object

createStackNavigator takes 2 arguments:

Navigation

StackNavigator - Basic Implementation

const Home = () => (
  <Text>Hello from Home</Text>
)

const Info = () => (
  <Text>Hello from Info</Text>
)

const AppStack = StackNavigator({
  Home: { screen: Home },
  Info: { screen: Info }
})

const App = createAppContainer(AppStack)

AppRegistry.registerComponent("App", () => App)
code

FlexBox

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'
}
exercise

training.infinite.red

Login Screen

Login Screen

  • Just like React
  • Use <TextInput/> instead of <input>
code

Tab Navigator

Tab Navigator

createBottomTabNavigator

import createBottomTabNavigator

import { createBottomTabNavigator } from "react-navigation"

Tab Navigator

Create Tab routes using screens or other navigators

const Tabs = createBottomTabNavigator(
  {
    Home: HomeScreen,
    Input: InputScreen 
  },
  {
    initialRouteName: "Home",
    tabBarOptions: {
      activeBackgroundColor: "orange",
      inactiveBackgroundColor: "yellow"
    }
  }
)
  •  BottomTabNavigatorConfig: object
  •  RouteConfigs: object

createBottomTabNavigator can also take 2 arguments:

code

Feed Screen

Feed

Screen

MST

Adding MST

npm i mobx mobx-react mobx-state-tree --save

Adding MST

npm i mobx mobx-react mobx-state-tree --save

MST

Pass along data/actions from a named store

inject
inject("rootStore")

MST

Make the screen pay attention to the store

observer
inject("rootStore")(observer(YourScreen))
code

Modal

Modal

Useful props:

  • animationType - String
    • "slide"
    • "fade"
    • "none"
  • transparent - Boolean
  • visible - Boolean

Class

builds

Modal 🛠

Cart Screen

AsyncStorage

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

Purchases Screen

Next Steps

  • add SignUpScreen

  • show subtotals and totals for purchases

  • actually protect routes

  • change price based on size

  • highlight active route in nav bar

  • better styles

  • animations

  • write more tests